0

I want to use MSL CombiTimeTable and be able to scale the parameters here from a scaling factor provided by another block or model. (The idea is to give flexibility for the user to express switching time points in sort of different units, eg. either as 60 seconds or as the liquid volume 120 mL that takes 120/2 seconds to pass by if the flow rate is 2 mL/s). The scaling is the same throughout a simulation. I hesitate whether to see scaling as a signal or a parameter but chose it to be a signal. Then I embed CombiTimeTable in a block with an interface of a scaling-signal and two parameter, see below.

model Test

    import Modelica.Blocks.Sources; 
    import Modelica.Blocks.Types; 
    import Modelica.Blocks.Interfaces.RealInput;
    import Modelica.Blocks.Interfaces.RealOutput;

    block ControlStep
        output RealOutput out;
        input RealInput scaling;        
        parameter Real start;
        parameter Real stop;
        Sources.CombiTimeTable loading(
            smoothness=Types.Smoothness.ConstantSegments,
            extrapolation=Types.Extrapolation.HoldLastPoint,
            table=[0, 0; start/scaling, 1; stop/scaling, 0]);
    equation
        out = loading.y[1]; 
    end ControlStep;

    model System
        ControlStep control_sample(start=0, stop=120);
        parameter Boolean scale_volume = true;
        Real F, Y, scaling;
    equation
        F = 2; 
        scaling = if scale_volume then F else 1;
        control_sample.scaling = scaling;
        Y = control_sample.out;
    end System;

 end Test;

Before I start a simulation I give values to parameters start and stop and also a parameter for if they should be given in terms of time or in terms of a scaled number. The code works for JModelica, but I am not very confident that the code have a sound structure. Here is some "initial" work to be done at start of simulation and I think of the concepts "initial algorithm" or "initial equation". The initial work is in my example spread out in two places as you see and consists of (expressed in a procedural way):

  1. Evaluate the value of the parameter"scale_volume"
  2. Get the value of F (here just equals 2 but generally defined based on several other parameters)
  3. Get the value of the variable scaling, i.e. F or 1
  4. Calculate the values in the table of CombiTimeTable

Would appreciate some comments, corrections, or suggestions of improvements even though the code do work in JModelica but actually not in OpenModelica.

janpeter
  • 681
  • 8
  • 22

1 Answers1

4

If scaling is no parameter you have a variability problem. I am surprised that JMoedlica accepts that.

In the assignment

loading(
  ...
            table=[0, 0; start/scaling, 1; stop/scaling, 0]);

you compute the parameter table from scaling. Hence, scaling must be a constant or a parameter.

If we change scaling and all related variables to parameters or final parameters, the code runs in OpenModelica v1.18.1 and in Dymola 2022x.

model Test

    import Modelica.Blocks.Sources;
    import Modelica.Blocks.Types;
    import Modelica.Units.SI.Time;

    block ControlStep
        parameter Real scaling;
        parameter Time start;
        parameter Time stop;
        Sources.CombiTimeTable loading(
            smoothness=Types.Smoothness.ConstantSegments,
            extrapolation=Types.Extrapolation.HoldLastPoint,
            table=[0, 0; start/scaling, 1; stop/scaling, 0]);
    end ControlStep;

    model System
        ControlStep control_sample(start=0, stop=120, scaling=scaling);
        parameter Boolean scale_volume = true;
        final parameter Real scaling = if scale_volume then F else 1;
        parameter Real F = 2;
        Real Y;
    equation 
        Y = control_sample.loading.y[1];
      annotation (experiment(StopTime=200));
    end System;

end Test;

Regarding your statement:

The scaling is the same throughout a simulation. I hesitate whether to see scaling as a signal or a parameter but chose it to be a signal.

Definitely use a parameter for that. This allows the Modelica translator to optimize your equations accordingly and in general should result in a faster model (at least a little).

Alternative: use timescale parameter

The CombiTimeTable also has a parameter which performs scaling: timeScale

For your minimal example using timeScale=1/scaling will give the same result as your approach.

model Test

    import Modelica.Blocks.Sources;
    import Modelica.Blocks.Types;
    import Modelica.Units.SI.Time;

    block ControlStep
        parameter Real scaling;
        parameter Time start;
        parameter Time stop;
        Sources.CombiTimeTable loading(
            timeScale=1/scaling,
            smoothness=Types.Smoothness.ConstantSegments,
            extrapolation=Types.Extrapolation.HoldLastPoint,
            table=[0, 0; start, 1; stop, 0]);
    end ControlStep;

    model System
        ControlStep control_sample(start=0, stop=120, scaling=scaling);
        parameter Boolean scale_volume = true;
        final parameter Real scaling = if scale_volume then F else 1;
        parameter Real F = 2;
        Real Y;
    equation 
        Y = control_sample.loading.y[1];
      annotation (experiment(StopTime=200));
    end System;

end Test;

marco
  • 5,944
  • 10
  • 22
  • Thanks! 1. Central to be able to before simulation change parameters: scale_volume, start, and stop. With your solution these are "locked". Might be due to requirements of CombiTimeTable? If I just introduce a dummy variable in System I can change that. 2. I do not understand the use of final before parameter here. Is it to satisfy some requirements from CombiTimeTable, or mainly to protect myself later coding errors? 3. You drop the use of RealOutput from ControlStep. Is that important? Tests made in JModelica 2.14. Also tried OpenModelica 1.20 cannot change scale_volume. – janpeter Apr 27 '22 at 15:01
  • The comments/questions above are for what you call "Alternative solution". – janpeter Apr 27 '22 at 15:25
  • 1
    1. The CombiTimetable defines Evaluate=true for timeScale. Hence it must be evaluated during compilation and therefore all parameters which are used to compute it. This is a drawback of this solution. Go with the original one if you want to change scaling without re-translation. 2. final parameters are computed from other parameters. Users can not change them. 3. just to make the code shorter. – marco Apr 27 '22 at 15:33
  • I changed to the first original solution. From experiments with JModelica I find that "final parameter" still makes it possible to after compilation to FMU change the value of scale_volume and at start of simulation the "final parameter" scaling is re-calculated. This is what I want! Thus "final" does NOT imply that the parameter is locked at compilation time. I hope I got right and what we all expect from the "final" concept. – janpeter Apr 27 '22 at 17:08
  • 1
    If you want to "lock" the parameter on translation you need the annotation `Evaluate=true`. Final means, that the equation will not change, but the result can obviously change with different values. – marco Apr 27 '22 at 18:05
  • So, if "final" is not there, the equation for scaling just provide a default value of the parameter and can be modified to any value. If "final" is there the parameter scaling follow the equation but the parameters it is based on may get values modified (depending on their declaration) and that propagate to scaling. And with the annotation Evaluate=true you lock that parameter up completely. Fritzson has a good example in 4.3.6. All works with OpenModelica 1.20 nightly build. – janpeter Apr 28 '22 at 06:15
  • 1
    Exactly, that's a good summary. – marco Apr 28 '22 at 15:37