I'd like to model a closed hydraulic cycle as one can find in the Modelica Standard Library/Fluid/Examples/HeatingSystem. With the heating system as well as with my (minimalistic) example I've got the same problem: The system is overdetermined.
You can find the HeatingSystem as a "bad example" in the following lecture, so I guess this is a well known problem, but I don't really get the point.
http://www.modprod.liu.se/MODPROD2011/1.252944/modprod2011-day2-talk3-Keynote-Francesco-Casella-Control-and-Modelica.pdf (page 20)
My example is:
a pump
model producer
pipe_flange w,k;
parameter Real a,b,c;
equation
w.p = k.p + a * k.Vp ^ 2 + b * k.Vp + c;
end producer;
a resistence
model consumer
pipe_flange w,k;
parameter Real rho;
parameter Real d_i;
parameter Real zeta;
equation
k.p = w.p - rho / 2 * ((w.Vp * 4) / 3.14 * d_i ^ 2) ^ 2 * zeta;
end consumer;
they are connected with a
connector pipe_flange
Real p;
flow Real Vp;
end pipe_flange;
The whole system is:
model System
consumer consumer1(rho = 1000, d_i = 0.06, zeta = 0.5);
producer producer1(a = -740741, b = -19630, c = 1070);
equation
connect(consumer1.w,producer1.w);
connect(consumer1.k,producer1.k);
end System;
Can anybody give me a hint what the problem is all about?
Are you sure your system is overdetermined? I'm; not sure how this can be since both your producer and consumer models are underdetermined.
As a general rule, the number of equations you need in a component will be equal to the number of flow variables across all its connectors + the number of internal variables (parameters do not count) + the number of outputs.
By this method, your producer model should have 2 equations (because it has 2 flow variable across all its connectors). Similarly, your consumer model should have 2 equations (Because it has two flow variables across all its connectors). So I don't see how you can generate too many equations.
Your model is also tricky because you are modeling the flow of momentum through your system (indicated by the presence of velocity on your connector as a flow variable). But your potential variable is pressure. There is no tracking of mass in your problem (as there usually is).
So, in summary, your component models definitely have an issue because they are "unbalanced" (according to the Modelica Specification) since they do not have the right number of equations. But even on a "physical" level, your formulation (pressure and velocity) is unusual in my experience and it seems to me that it could lead to problems as well once the equation balance issue is overcome.
Maybe it helps to introduce a so called loop-breaker component.
For a closed hydraulic cycle this could be an expansion vessel or storage tank with a variable level
(such a component will also exist in reality).
Related
We are modeling various industrial component blocks, with each having CAPEX, labour cost, maintenance cost, total OPEX, etc. We would like to have 1 block, in the best case not wired to the other blocks, to account for the total OPEX, total CAPEX, total labour costs, etc. induced by the blocks present in a model : the number of blocks is not fixed. Is there a way of not connecting the blocks with a wire ?
In case there is no way, we found the solution of using the RealOutput y vector, as defined in Modelica.Blocks.Interfaces.MO : nout is defined as the number of actual variables we would like to add up (e.g. if CAPEX, OPEX and maintenance are of interest, then nout = n = 3). However, we struggle for 2 points :
How can we pass a matrix through this RealOutput ? This would be useful for instance when the CAPEX has 3 values : estimated, optimistic and pessimistic.
How can we take up this y in only 1 block ? For now we managed to use n Modelica.Blocks.Math.MultiSum blocks to take up each variable separately, but is there a way of adding them up respectively, but in the same block ?
Thank you already for your much appreciated help and answers !
I think you should be able to do this with the inner/outer construct and a custom connector with a flow variable for, e.g., your capex, as demonstrated in section 5.8 of Fritzson's book "Principles of Object-Oriented Modeling and Simulation with Modelica 3.3".
I could have sworn there is already an example around that sums masses of components to a total, but I could not find it anywhere...
package SO_69945088
model System
FinancialAggregator fin_totals() "Collects financial info";
inner CapexConn common_connection "autoshared connection";
Component comp1(capex_info.amount={0, 3, 5});
Component comp2(capex_info.amount={1, 10, 12});
Component comp3(capex_info.amount={5, 6, 7});
equation
//Conveniently collect financial info in fin_totals
connect(common_connection, fin_totals.agg_conn);
end System;
connector CapexConn
// the amount being a "flow" variables means all contributions
// sum at a connection point.
flow Real[3] amount;
// every "flow" variable should have a non-flow variable,
// at least for "physical" connections. Let's add a dummy:
Real [3] period;
end CapexConn;
model CapexEmitter
CapexConn conn;
Real[3] amount = fill(0, 3);
Real[3] period;
equation
// Here you could also have more logic, like computing emitted capex
// depending on the period
conn.amount = -amount; //negative because of sign of flow direction in connectors
conn.period = period;
end CapexEmitter;
model Component "Industrial component block with capex tracking"
// (you would extend your other components from this to use it)
outer CapexConn common_connection; // make outside connection visible
CapexEmitter capex_info;
equation
// all Component instances automatically connect, without manual wiring
connect(capex_info.conn, common_connection);
end Component;
model FinancialAggregator
CapexConn agg_conn;
Real[3] capexsum;
Real period[3] = {1,1,1};
equation
capexsum = agg_conn.amount;
period = agg_conn.period;
end FinancialAggregator;
end SO_69945088;
Simulating System gives a fin_totals.capexsum of {6, 19, 24} (optimistic, estimated, pessimistic).
This should give you a starting point showing the principles.
I am having a problem that could be easily solved in a causal environment like Fortran, but has proved difficult in Modelica, considering my limited knowledge
Consider a volume with an inlet and outlet. The inlet mass flow rate is specified, while the outlet mass flow is calculated based on pressure in the volume. When pressure in the volume goes above a set point, the outlet area starts to increase linearly from its initial value to a max value and remains fixed afterwards. In other words:
A = min( const * (t - t*) + A_0, A_max)
if p > p_set
where t* = the time at which pressure in the volume exceeds the set pressure.
The question is: there's a function to capture t* during the simulation? OR how could the model be programmed to do it? I have tried a number of ways, but models are never closed. Thoughts are welcome and appreciated!
Happy holidays/New Year!
Mohammad
You may find the sample and hold example in my book useful. It uses sampling based on time whereas you probably want it based on your pressure value. But the principle is the same. That will allow you to record the time at which your event occurred.
Addressing your specific case, the following (untested) code is probably pretty close to what you want:
...
Modelica.SIunits.Time t_star=-1;
equation
when p >= p_set then
t_star = time;
end when;
A = if t_star<0 then A_max else min(const*(t - t_star) + A_0, A_max);
I want to know if a model can be inversed in modelica. (here inverse means: if in causal statement y= x +a; x and a are input and y is output; but if I want to find 'x' as output and 'y' and 'a' as input, the model is called reversed/inversed model) For example, if I have compressor with input air port and output air port, and port has variables associated with it are pressure(P), temperature(T) and mass flow rate(mdot). I have simple steady state model containing three equations as follow:
OutPort.mdot = InPort.mdot
OutPort.P = rc * InPort.P
OutPort.T = InPort.T * (1 + rc[ (gamma-1)/gamma) - 1][/sup] / eta);
Here, rc, gamma and eta are compression ratio, ratio of specific heat capacitites and efficiency of compressor respectively.
I want to know, if I know values of : gamma, eta, OutPort.mdot, OutPort.P and OutPort.T and InPort.P and InPort.T, can I find the value of rc.
Can I find values of rc and how should be the model of compressor with above equation in Modelica. As far as I know, there are some variables designated as parameters which can not be changed during simulation. How the modelica model should be with above equations
Thanks
Yes, this should not be a problem as long as you make sure that rc is not a parameter, but a normal variable, and you supply the appropriate number of known quantities to achieve a balanced system (roughly, number of unknowns matches number of equations).
E.g. in your case if you know/supply OutPort.P and InPort.P, rc is already determined from eq 2. Then, in the third equation, there are no unknowns left, so either the temperature values are consistent with the equation or you (preferably) leave one temperature value undetermined.
In addition if you only want to compute the parameter rc during steady-state initialization i.e. that nothing changes with time that is also possible:
...
parameter Real rc(fixed=false);
initial equation
Inport.mdot=12; // Or something else indirectly determining rc.
The fixed=false means that rc is indirectly determined from the initialization. However, if the model is not completely stationary it will only find the correct rc during the initialization and then use that afterwards.
Rheological models are usually build using three (or four) basics elements, which are :
The spring (existing in Modelica.Mechanics.Translational.Components for example). Its equation is f = c * (s_rel - s_rel0);
The damper (dashpot) (also existing in Modelica.Mechanics.Translational.Components). Its equation is f = d * v_rel; for a linear damper, an could be easily modified to model a non-linear damper : f = d * v_rel^(1/n);
The slider, not existing (as far as I know) in this library... It's equation is abs(f)<= flim. Unfortunately, I don't really understand how I could write the corresponding Modelica model...
I think this model should extend Modelica.Mechanics.Translational.Interfaces.PartialCompliant, but the problem is that f (the force measured between flange_b and flange_a) should be modified only when it's greater than flim...
If the slider extends PartialCompliant, it means that it already follows the equations flange_b.f = f; and flange_a.f = -f;
Adding the equation f = if abs(f)>flim then sign(f)*flim else f; gives me an error "An independent subset of the model has imbalanced number of equations and variables", which I couldn't really explain, even if I understand that if abs(f)<=flim, the equation f = f is useless...
Actually, the slider element doesn't generate a new force (just like the spring does, depending on its strain, or just like the damper does, depending on its strain rate). The force is an input for the slider element, which is sometime modified (when this force becomes greater than the limit allowed by the element). That's why I don't really understand if I should define this force as an input or an output....
If you have any suggestion, I would greatly appreciate it ! Thanks
After the first two comments, I decided to add a picture that, I hope, will help you to understand the behaviour I'm trying to model.
On the left, you can see the four elements used to develop rheological models :
a : the spring
b : the linear damper (dashpot)
c : the non-linear damper
d : the slider
On the right, you can see the behaviour I'm trying to reproduce : a and b are two associations with springs and c and d are respectively the expected stress / strain curves. I'm trying to model the same behaviour, except that I'm thinking in terms of force and not stress. As i said in the comment to Marco's answer, the curve a reminds me the behaviour of a diode :
if the force applied to the component is less than the sliding limit, there is no relative displacement between the two flanges
if the force becomes greater than the sliding limit, the force transmitted by the system equals the limit and there is relative displacement between flanges
I can't be sure, but I suspect what you are really trying to model here is Coulomb friction (i.e. a constant force that always opposes the direction of motion). If so, there is already a component in the Modelica Standard Library, called MassWithStopAndFriction, that models that (and several other flavors of friction). The wrinkle is that it is bundled with inertia.
If you don't want the inertia effect it might be possible to set the inertia to zero. I suspect that could cause a singularity. One way you might be able to avoid the singularity is to "evaluate" the parameter (at least that is what it is called in Dymola when you set the Evaluate flat to be true in the command line). No promises whether that will work since it is model and tool dependent whether such a simplification can be properly handled.
If Coulomb friction is what you want and you really don't want inertia and the approach above doesn't work, let me know and I think I can create a simple model that will work (so long as you don't have inertia).
A few considerations:
- The force is not an input and neither an output, but it is just a relation that you add into the component in order to define how the force will be propagated between the two translational flanges of the component. When you deal with acausal connectors I think it is better to think about the degrees of freedom of your component instead of inputs and outputs. In this case you have two connectors and independently at which one of the two frames you will recieve informations about the force, the equation you implement will define how that information will be propagated to the other frame.
- I tested this:
model slider
extends
Modelica.Mechanics.Translational.Interfaces.PartialCompliantWithRelativeStates;
parameter Real flim = 1;
equation
f = if abs(f)>flim then sign(f)*flim else f;
end slider;
on Dymola and it works. It is correct modelica code so it should be work also in OpenModelica, I can't think of a reason why it should be seen as an unbalance mathematical model.
I hope this helps,
Marco
Just starting with Modelica and having trouble understanding how it works.
In the below 'method' of the model, qInflow and qOutflow are used in the second line to evaluate der(h), but they have not received a value yet! (they were not defined in the 'data' of the method)? In what order is the code executed.
equation
assert(minV >= 0, "minV must be greater or equal to zero");
der(h)=(qInflow - qOutflow)/area;
qInflow=if time > 150 then 3*flowLevel else flowLevel;
qOutflow=Functions.LimitValue(minV, maxV, -flowGain*outCtr);
error=ref - h;
der(x)=error/T;
outCtr=K*(error + x);
end FlatTank;
From http://www.mathcore.com/resources/documents/ie_tank_system.pdf
This is an understandable point of confusion when coming from languages and systems that utilize imperative semantics. But Modelica doesn't work like that.
When working with Modelica it is important to understand that an equation section contains equations, not assignments. Consider this, if I gave you the following equations:
x + y = 3;
x + 2*y = 5;
If you understand that this is a mathematical context, you can then determine that x must have a value of 1 and y must have a value of 2. In other words, you have to solve a system of simultaneous equations. You'll note that the left hand side of these equations are not variables (in general), they are expressions. An equation is simply a relationship that equates one expression, on the left hand side, with another expression, on the right hand side. Furthermore, this relationship is always true and so order is irrelevant.
This is quite different from imperative programming languages with imperative semantics. But it is also very powerful because you can state these relationships (linear systems of equations, non-linear systems of equations, implicit equations, etc) and the compiler will work out the most efficient way to solve them.
Getting back to your example, when you look at the code in your question you are interpreting those equations as assignment statements. This notion is reinforced because they just happen to have variables on the left hand sides. But they are really equations. In an equation based system, you do not worry about whether a given variable has been assigned to previously. Instead, the requirement is simply that for every variable there exists (somewhere) an equation and that there are no extra equations. In other words, you should have the same number of variables as unknowns and that the system of equations has a unique solution. That is all that Modelica requires.
Now, Modelica supports the kind of imperative semantics you are used to. But they are only to be used in special cases because they constrain the interpretation of the mathematical behavior in such a way that it interferes with the symbolic manipulation that allows Modelica compilers to generate really fast code. So it is more than a question of style. You should use equations if at all possible and algorithms in Modelica should only be used as a last resort.
One last note. Some people may be wondering "Are you telling me that these equations will be put into some giant system of equations and solved by matrix inversion or Newton-Raphson or something? Why make it so complicated when it could obviously be solved in a much easier way!" But it will not be solved as a giant system of equations. If it can be solved as a simple set of assignments it will. That is one (among many) of the different symbolic manipulation techniques that will be applied. In fact, this is a key point about Modelica...you don't need to worry about optimizing the solution method, the tool will take care of that. And more importantly, if you connect components in such a way that a simultaneous system does arise, you don't need to worry about that either. Modelica tools can handle such "algebraic loops" for you, they will optimize it to find the most computationally efficient formulation and won't depend on you reformulating your model for those cases.
Does that help?
You cannot know the execution order of the equations in a Modelica model until you run a Modelica tool on it (you can re-order any equation in the source model and get the same result). And then the order is only true for this tool with the settings you used.
This was the order chosen by the OpenModelica compiler (omc +s +simCodeTarget=Dump model.mo):
error = ref - h;
outCtr = K * (error + x);
der(x) = DIVISION(error, T, #SHARED_LITERAL_2(String#);
qOutflow = LimitValue(minV, maxV, (-flowGain) * outCtr);
qInflow = if time > 150.0 then 3.0 * flowLevel else flowLevel;
der(h) = DIVISION(qInflow - qOutflow, area, #SHARED_LITERAL_3(String#);
This example was a little boring because the left and right sides of no equation changed place (h = error - ref would be viable if h was not chosen as a state variable, etc).