modelicaopenmodelicajmodelicasystemmodeler

OpenModelica complains about a negative value which can't be negative


Following this question I have modified the energy based controller which I have described here to avoid negative values inside the sqrt:

model Model
  //constants
  parameter Real m = 1;
  parameter Real k = 2;
  parameter Real Fmax = 3;
  parameter Real x0 = 1;
  parameter Real x1 = 2;
  parameter Real t1 = 5;
  parameter Real v0 = -2;

  //variables
  Real x, v, a, xy, F, vm, K;

initial equation
  x = x0;
  v = v0;

equation
  v = der(x);
  a = der(v);
  m * a + k * x = F;

algorithm
  if time < t1 then
    xy := x0;
  else
    xy := x1;
  end if;
  
  K := Fmax * abs(xy - x) + k * (xy^2 - x^2) / 2;
  
  if abs(xy - x) < 1e-6 then
    F := k * x;
  else
    if K > 0 then
      vm := sign(xy - x) * sqrt(2 * K / m);
      F := Fmax * sign(vm - v);
    else
      F := Fmax * sign(x - xy);
    end if;
  end if;
  
  annotation(
    experiment(StartTime = 0, StopTime = 20, Tolerance = 1e-06, Interval = 0.001),
    __OpenModelica_simulationFlags(lv = "LOG_STATS", outputFormat = "mat", s = "euler"));
end Model;

However, it keeps giving me the error:

The following assertion has been violated at time 7.170000

Model error: Argument of sqrt(K / m) was -1.77973e-005 should be >= 0

Integrator attempt to handle a problem with a called assert.

The following assertion has been violated at time 7.169500

Model error: Argument of sqrt(K / m) was -6.5459e-006 should be >= 0

model terminate | Simulation terminated by an assert at the time: 7.1695

STATISTICS 

Simulation process failed. Exited with code -1.

I would appreciate if you could help me know what is the problem and how I can solve it.


Solution

  • The code you created does event localization to find out when the condition in the if-statements becomes true and/or false. During this search it is possible that the expression in the square-root becomes negative although you 'avoided' it with the if-statement.

    Try reading this and to apply the solution presented there. Spoiler: It basically comes down to adding a noEvent() statement for you Boolean condition...