I was wondering how the following is possible in Modelica:
suppose variables a,b
Timetable object c
equation
if a>c.y then
b = f(a) // with f a mathematical function
else
b = g(a) // with g a mathematical function
end if;
der(a) = h(a,b) //with h a mathematical function
How can Modelica determine which case of the if statement is true? It cannot compute the value of "a" without the value of "b", which is determined in the if statement.
First, note that a is state (at least based on the equations you have shown). This means that at the current time a will be known. From your description, c is also known (it is a function of time, apparently). So at any point in time, we know which branch of the if statement will be taken.
So for any given time we can compute b and therefore der(a). The real question is at what point does the condition in the if statement change.
The answer is that a "monitor" function is established (by the Modelica compiler) and when that monitor function crosses zero then the Modelica runtime will react by stopping integration at that point and then restarting with the integration (using the other branch). This is because the conditional expression in an if statement implicitly generates events.
Another way to think about this is that there is a "hidden" boolean variable that indicates whether we take on branch or the other. At first, this sounds crazy because you assume that the Modelica runtime will take the branch based on whether a>c.y but that isn't actually the case. What it does is determine the initial value of the boolean based on the value of a>c.y at the start of the simulation and then it tries to figure out when it actually changes. It doesn't really evaluate a>c.y all the time. This leads to strange situations where one branch is executed even though it shouldn't. This will happen in Modelica and is related to candidate solutions generated while the Modelica runtime is trying to determine where the event occurred.
I know it sounds confusing, but if you embrace this "hidden boolean variable" notion and understand that it doesn't change until the Modelica runtime can definitively identify the point at which the change should occur (based on some candidate solution trajectory), it all makes sense.
I hope that helps.
Related
I am building a circuit model for a transformer which models the effects of hysteresis. It does so using the Matlab function block on the right, and works successfully when tested in isolation. However, the value of the magnetising inductance Lm depends on calculations requiring the value of Im. But Simulink cannot determine the value of Im without the value of Lm, thus forming an algebraic loop.
However, I have the initial value for the inductance, Lm_initial loaded into the workspace. With this, I should be able to solve for the first Im value, which can be used to determine the next Lm, and so on. However, specifying Lm_initial in the variable inductor's properties doesn't work; Simulink tries to evaluate Lm with the nonexistent 'phi' and 'Im' values rather than trying to solve for an initial Im using the value of the initial inductance.
I have tried solutions involving commenting/uncommenting blocks and implementing further subsystems which activate/deactivate depending on the time step, as well as unit delays, but these run into issues regarding tracking time for calculating the derivatives or output very incorrect/noisy waveforms.
Is there a relatively simple solution for this case? The problem appears as if it'd be relatively simple to solve, but I cannot seem to find a workaround for this.
Transformer Equivalent Model
The exact placement of the unit delay in the loop might be the key here: try to place the unit delay between the [lm] GoTo block and the lm input of your MATLAB function block fcn, that should work. And set the initial condition parameter to Lm_initial.
I build a simple model to understand the concept of "Discrete expressions", here is the code:
model Trywhen
parameter Real B[ :] = {1.0, 2.0, 3.0};
algorithm
when time>=0.5 then
Modelica.Utilities.Streams.print("message");
end when;
annotation (uses(Modelica(version="3.2.3")));
end Trywhen;
But when checking the model, I got an error showing that "time==0.5" isn't a discrete expression.
If I change time==0.5 to time>=0.5, the model would pass the check.
And if I use if-clause to when-clause, the model works fine but with a warning showing that "Variables of type Real cannot be compared for equality."
My questions are:
Why time==0.5 is NOT a discrete expression?
Why Variables of type Real cannot be compared for equality? It seems common when comparing two variables of type Real.
The first question is not important, since time==0.5 is not allowed.
The second question is the important one:
Comparing reals for equality is common in other languages, and also a common source of errors - unless special care is taken.
Merely using the floating point compare of the processor is a really bad idea on idea on some processors (like Intel) that mix 80-bit and 64-bit floating point numbers (or comes with a performance penalty), and also in other cases it may not work as intended. In this case 0.5 can be represented as a floating point number, but 0.1 and 0.2 cannot.
Often abs(x-y)<eps is a good alternative, but it depends on the intended use and the eps depends on additional factors; not only machine precision but also which algorithm is used to compute x and y and its error propagation.
In Modelica the problems are worse than in many other languages, since tools are allowed to optimize expressions a lot more (including symbolic manipulations) - which makes it even harder to figure out a good value for eps.
All those problems mean that it was decided to not allow comparison for equality - and require something more appropriate.
In particular if you know that you will only approach equality from one direction you can avoid many of the problems. In this case time is increasing, so if it has been >0.5 at an event it will not be <=0.5 at a later event, and when will only trigger the first time the expression becomes true.
Therefore when time>=0.5 will only trigger once, and will trigger about when time==0.5, so it is a good alternative. However, there might be some numerical inaccuracies and thus it might trigger at 0.500000000000001.
The noEvent operator in Modelica doesn't use iteration to find the precise time instant in which the event was triggered.
It seems this would cause calculation error, here is an example I find on the following website
https://mbe.modelica.university/behavior/discrete/decay/
So Do I have to ensure the function is smooth when using noEvent operator?
What's the purpose of using noEvent operator if it can't ensure accuracy?
Although the question is already answered I would like to add some points, as I think it could be useful for many.
There are some common reasons to use the noEvent() statement:
Guarding expressions: This is used to prevent a function from being evaluated outside of their validity range. A typical example is der(x) = if x>=0 then sqrt(x) else 0; which would work perfectly in most common programming languages. This doesn't work always in Modelica for the following reason: When searching for the time when the condition x>=0 becomes false, it is possible that both branches are evaluated with values of x varying around 0. The same fact is mentioned in the screenshot posted by marvel This results in a crash if the square root of a negative x is evaluated. Therefore der(x) = if noEvent(x>=0) then -sqrt(x) else 0; Is used to suppress the iteration to search for the crossing time, leaving the handling of the discontinuity to the solver (often referred to as "expressions are taken literally instead of generating crossing functions"). In case of a variable step-size solver being used, this makes the solver reduce the step-size to meet it's relative error tolerance, which will likely result in degraded performance. Additionally this can be critical if the function described is not smooth enough resulting in non-precise or even instable simulations.
Continuous Expressions: When a function is continuous there is actually no event necessary. This comes down to the fact, that events are used to describe discontinuities. So if there is none, usually the event is simply superfluous and can therefore be suppressed. This is actually covered by the smooth() operator in Modelica, but the specification says, that a tool is free to still generate events. To my experience, tools generate events if the change to the function is relatively big. Therefore it can make sense to have a noEvent() within a smooth().
Avoid chattering: noEvent can help here but actually chattering is a more general problem. Therefore I'd recommend to solve issues related to chattering by re-building the model.
If none of the above is true the use of noEvent should be considered carefully.
I think the Modelica Language Specification Version 3.4 Section 3.7.3.2. and Section 8.5. will help you out here (in case you have not already checked this).
From what i know it should only be used for efficiency reasons and in most cases one should use smooth() instead or in conjunction.
Based on the two different ways of dealing with the event. If using noEvent operator, there is no halt of the integration, but the numerical solver assumes that the function should be smooth, with unsmooth functions, there would be numerical errors.
I'm building electrical models that use a complex number or just the real part of a variable in a connector. Depending on a boolean I am switching between the two equation sets.
My question is: What is the best way to handle the imaginary when I don't want to use it. Setting it to zero leads to problems when I connect other components that do the same because the variable is overdetermined.
Is there a way to disable the imaginary part or change the connector so it only has a real variable if I use the real valued equation set?
Below I pasted the equation set.
equation
if transient then
v = Complex(Vnom*cos(theta + phiV),0); // how can I avoid setting im to zero here?
else
v = Complex(Vnom*cos(phiV), Vnom*sin(phiV));
end if;
Thank you in advance for your help!
There is actually an analogous issue in both fluid problems and multibody problems. In the fluid case, the "equation of state" changes which influences how many degrees of freedom there are. In the case of multibody systems, you have the issue that you need some kind of mechanical ground element but if you have a "loop" in your components it will be over constrained.
It seems to me your issue is closer to the fluid problem (but I don't now the AC domain well at all, so I'm just guessing). In that case, what you can do is cascade down through the hierarchy information about exactly what kind of formulation to use. If you want to use different connectors, then you use a replaceable package to cascade new connector types through the hierarchy. This gets kind of involved. If, however, you just want to know whether to use one equation or the other (across a bunch of components), then you can just cascade a (Boolean?) parameter value through everything (e.g., your transient flag).
Another thing you might consider is using inner and outer to implicitly cascade a parameter through your hierarchy. Several libraries use a so-called world object to provide global information about the model. In this way, you can put an inner world object at the root and all components within the same hierarchy can access it using the outer keyword. I try to avoid inner/outer and use the more explicit parameter cascading. But it is up to you.
If I'm getting a anonymous operator from a user I would like to test (extremely quickly) if the operator is linear. Is there a standard way to do this? I have no way of doing symbolic operators, or parsing the function. Is the only way trying some random functions (what random functions do I choose) and seeing if they satisfy linearity??
Thanks in advance.
Context:
User supplies a black box operator, that is a function which takes functions to functions.
I can give the operator a function and I get a function back. I want to determine if the operator is linear? Is there a standard fast method which gives me high confidence?
No, not without sweeping the entire parameter space. Imagine the following:
#(f) #(x) f(x) + (x == 1e6)
This operator is non-linear, but there's no way of knowing that unless you happen to test at x == 1e6.
UPDATE
As others have suggested, it may be "good enough" to determine a domain of interest, and check for linearity at periodic intervals across the domain. This may give you false positives (i.e. suggest an operator is linear when in fact it's non-linear), but never false negatives.
This is information the user should supply. Add a parameter linear true/false, default to false (I'm assuming that the code for non-linear will work for linear too, just taking more time).
The problem with random testing is that you will classify a non-linear function as linear sooner or later, and then the user has a problem, because your function unpredictably produces wrong results (depending on which points you pick randomly), that may be reasonably close to the correct results, ie people may not notice for a loooong time --> this is a recipe for disaster.
Really, the user should know this in the first place, its very important to avoid false positives and as said before there is no completely reliable way to test this. Save yourself the trouble and add an additional parameter.