I am trying to model a switch to swap between a prescribedHeatFlow and a prescribedTemperature. Therefore, I tried the following model:
model HeatSwitch
extends Modelica.Blocks.Interfaces.partialBooleanBlockIcon;
Modelica.Blocks.Interfaces.RealInput Q_flow_in(unit="W")
"Connector of first Real input signal"
annotation (Placement(transformation(extent={{-140,60},{-100,100}})));
Modelica.Blocks.Interfaces.BooleanInput u2 "If true use Q_flow_in, else T_in"
annotation (Placement(transformation(extent={{-140,-20},{-100,20}})));
Modelica.Blocks.Interfaces.RealInput T_in(unit="K", displayUnit="degC")
"Connector of second Real input signal"
annotation (Placement(transformation(extent={{-140,-100},{-100,-60}})));
Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_b port
annotation (Placement(transformation(extent={{82,-18},{116,16}})));
equation
if u2 then
port.Q_flow = -Q_flow_in;
else
port.T = T_in;
end if;
annotation (
Diagram(coordinateSystem(preserveAspectRatio=false, extent={{-100,-80},{100,
80}})),
Icon(coordinateSystem(preserveAspectRatio=true, extent={{-100,-80},{100,80}}),
graphics={
Line(points={{12.0,0.0},{100.0,0.0}}, color={191,0,0}),
Line(points={{-100.0,0.0},{-40.0,0.0}}, color={255,0,255}),
Line(points={{-100.0,-80.0},{-40.0,-80.0},{-40.0,-80.0}}, color={191,0,0}),
Line(points={{-40.0,12.0},{-40.0,-12.0}}, color={255,0,255}),
Line(points={{-100.0,80.0},{-38.0,80.0}}, color={191,0,0}),
Line(
points={{-38.0,80.0},{6.0,2.0}},
color={191,0,0},
thickness=1.0),
Ellipse(
lineColor={0,0,255},
pattern=LinePattern.None,
fillPattern=FillPattern.Solid,
extent={{2.0,-8.0},{18.0,8.0}})}),
Documentation(info="<html>
</html>", revisions="<html>
</html>"));
end HeatSwitch;
The following test model is a small example:
model TestHeatFlowSwitch
Modelica.Blocks.Sources.Constant constHeatFlow(k=0)
annotation (Placement(transformation(extent={{-72,16},{-56,32}})));
HeatSwitch prescribedHeatSwitch
annotation (Placement(transformation(extent={{-38,-10},{-26,0}})));
Modelica.Blocks.Sources.Constant constTemp(k=293.15)
annotation (Placement(transformation(extent={{-74,-54},{-54,-34}})));
Modelica.Blocks.Sources.BooleanExpression boolForSwitch(y=time > 0.5)
annotation (Placement(transformation(extent={{-74,-22},{-54,-2}})));
Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heatCapacitor(C=10000)
annotation (Placement(transformation(extent={{10,2},{30,22}})));
equation
connect(constHeatFlow.y, prescribedHeatSwitch.Q_flow_in) annotation (Line(
points={{-55.2,24},{-48,24},{-48,0},{-39.2,0}}, color={0,0,127}));
connect(constTemp.y, prescribedHeatSwitch.T_in) annotation (Line(points={{-53,
-44},{-44,-44},{-44,-10},{-39.2,-10}}, color={0,0,127}));
connect(boolForSwitch.y, prescribedHeatSwitch.u2) annotation (Line(points={{-53,
-12},{-48,-12},{-48,-5},{-39.2,-5}}, color={255,0,255}));
connect(prescribedHeatSwitch.port, heatCapacitor.port) annotation (Line(
points={{-26.06,-5.0625},{20,-5.0625},{20,2}}, color={191,0,0}));
annotation (uses(Modelica(version="3.2.2")));
end TestHeatFlowSwitch;
Due to discrete changes in the input, errors are thrown during the simulation.
Mainly, I would like to express my problem with this example. Now I am looking for a smart way to implement such a model.
Thanks a lot in advance for any helpful answer.
In current Modelica (3.2.2) not possible to change the input from an across to a flow variable during simulation. In this case the underlying system of equations would have to be translated again as the causality of the assignments change. If you are eager to read more on this topic: https://www.inf.ethz.ch/personal/cellier/PhD/zimmer_phd.pdf
It is actually a bit strange that Dymola even tries to simulate the model in my opinion...
I think the easiest solution to switch from a power flow to a temperature input, would be to add a "thermal switch" to the source of temperature. Then connect the switch and the source of power-flow to the thermal capacity. The switch itself could be similar to the electric switch in the MSL (Modelica.Electrical.Analog.Ideal.IdealOpeningSwitch) having a very high resistance when turned off or very low resistance when turned on. When the switch is in off state nearly the full power would be transferred to the capacity, if it has low resistance, the power is transferred to the source of temperature and the capacity would have a temperature close to the one of the source.
Related
I have used the Modelica "stream" concept for connectors for some time. What I understand the functions inStream() and actualStream() are designed for use
when the model has a volume. But here are important cases where there is no
volume and you need for convenience stick to the connectors you have. One example is a ProbeSensor that is mounted into a reactor volume and measures one of the species in the liquid, but does not "consume" any liquid.
The code below works using inStream(). However, I am inclined to instead use actualStream() since it "handles zero flow". But if I do the change the model does not compile and I get translation error that here are more variable than equations.
Is the code with inStream() after all correct?
Or how should it be modified?
LiquidCon
stream Real[2] c;
flow Real F;
Real p;
end LiquidCon;
block ProbeSensor
LiquidCon probe;
output RealOutput out;
constant Integer component = 2 "The liquidphase component measured index";
parameter Real T (unit="h") = 0.05 "Time constant of measurement";
parameter Real x_0 = 0.0 "Initial state of measurement device";
Real x(start=x_0, fixed=true) "State variable measurement device";
Real p (unit="bar") "Pressure";
equation
probe.F = 0;
p = probe.p;
for i in 1:2 loop
if (i==component) then
T*der(x) + x = inStream(probe.c[component]);
inStream(probe.c[component]) = probe.c[component];
out = x;
else
inStream(probe.c[i]) = probe.c[i];
end if;
end for;
end ProbeSensor;
Yes, inStream() is the best solution for this type of sensor/probe model.
inStream() gives you a value for the hypothetical case of fluid streaming into the component model. No matter what the real flow direction is (in this case 0 flow). And that's perfectly right for sensors.
As a general rule: If you can do something with inStream() than go for it. Only use actualStream() if you really need it.
Reason for that: actualStream() is basically an if expression. And that is always nonlinear, which can easily produce ugly nonlinear systems in the overall system model.
Here is a minimum working example of some expandable connector usage occuring in my models:
model TestExpandableConnector
expandable connector ControlBus
extends Modelica.Icons.SignalBus;
Real signal1;
Real signal2;
end ControlBus;
ControlBus controlBus;
// example models to connect signals to
Modelica.Blocks.Math.Gain gain1;
Modelica.Blocks.Math.Gain gain2;
// and so on
equation
connect(controlBus.signal1, gain1.u);
connect(controlBus.signal2, gain2.u);
// and so on
end TestExpandableConnector;
This works fine and no concerns here.
Note that normally this model would be created in the diagram layer with graphical objects and connections between the bus and the components (gains in this case).
While the above example is trivial, in many real world examples I have many connections emerging from that one expandable connector. This quickly can become messy in the diagram layer and I'm trying to learn/develop some best practices here for cleaning up the diagrams.
One option seems to be to use the RealExpression block in a way almost equivalent to Simulink's From/Goto elements. For example:
model TestExpandableConnectorRevised
expandable connector ControlBus
extends Modelica.Icons.SignalBus;
Real signal1;
Real signal2;
end ControlBus;
ControlBus controlBus;
// example models to connect signals to
Modelica.Blocks.Math.Gain gain1;
Modelica.Blocks.Math.Gain gain2;
// and so on
// using RealEpressions like goto tags
Modelica.Blocks.Sources.RealExpression realExpression1(y=controlBus.signal1);
Modelica.Blocks.Sources.RealExpression realExpression2(y=controlBus.signal2);
// and so on
equation
connect(realExpression1.y, gain1.u);
connect(realExpression2.y, gain2.u);
// and so on
end TestExpandableConnectorRevised;
Now with this change, Dymola complains about this being illegal since causality cannot be determined. I seem to be able to resolve this last issue by either 1) adding the "input" prefix to the signal1 and signal2 declarations in the bus, or 2) positioning the declaration for the realExpressions before the contolBus declaration (this 2nd solution is a bit odd to me).
Overall, I'm reasonably happy with these solutions from a decluttering my diagram point of view, but they also feel at least a little bit "hacky". My basic goal in this question is to inquire if this approach is OK or if it's a bad idea? Additionally, if there are any other suggestions regarding how to handle the organization of all the connections in a big model (especially with expandable connectors), I'm all ears. As an additional thought, it seems to a me that a more dedicated "From/Goto" feature for the Modelica language might be really nice in Modelica, purely for the purpose of decluttering diagrams but being exactly equivalent to a connect statement under the hood.
Dymola complains that
The variable controlBus.signal1 is part of an expandable connector, and was only used
outside of connect. That is not legal since we cannot determine its causality.
Your revised solution works, as soon as you write the signal somewhere using a connect
statement. Below I further reduced your example to contain only signal1. An additional real expression is used to set its value.
model TestExpandableConnectorRevised
expandable connector ControlBus
Real signal1;
end ControlBus;
ControlBus controlBus;
Modelica.Blocks.Math.Gain gain1;
Modelica.Blocks.Sources.RealExpression realExpression1(y=controlBus.signal1);
// Added to write the bus signal
Modelica.Blocks.Sources.RealExpression realExpression3(y=1);
equation
connect(realExpression1.y, gain1.u);
// Added to write the bus signal
connect(realExpression3.y, controlBus.signal1);
end TestExpandableConnectorRevised;
This example compiles in Dymola pedantic mode and OpenModelica, so it should be perfectly fine.
Alternative approach using bus adapters
As you see, expandable connectors are full of pitfalls. The problem above can also happen easily if you decide to rename signal1 to mysignal on the expandable connector, but forget to update the connect statement to connect(realExpression3.y, controlBus.mysignal).
Therefore some Modelica libraries decided read and write bus signals only via bus adapters. You have to create 2 additional blocks for every variable: one to read and one to write its value. This is a lot of boring work, but it avoids the problem above.
Here is a minimal example to read and write signal1.
package BusAdapters
partial block BusWriter
// Dialog allows to set the value of y in the parameter window, like for the real expression
Modelica.Blocks.Interfaces.RealInput u annotation (Dialog);
ControlBus controlBus;
end BusWriter;
block Write_signal1
extends BusWriter;
equation
connect(u, controlBus.signal1);
end Write_signal1;
partial block BusReader
Modelica.Blocks.Interfaces.RealOutput y;
ControlBus controlBus;
end BusReader;
block Read_signal1
extends BusReader;
equation
connect(y, controlBus.signal1);
end Read_signal1;
expandable connector ControlBus
extends Modelica.Icons.SignalBus;
Real signal1;
end ControlBus;
model TestBusConnectors
ControlBus controlBus;
Modelica.Blocks.Math.Gain gain1;
// setting bus variables: using modifiers in write blocks
Write_signal1 write1(u=sin(time));
// accessing bus variables part 1: creating instance of reader
Read_signal1 read1;
equation
// connect all read and write blocks to the same bus instance
connect(write1.controlBus, controlBus);
connect(read1.controlBus, controlBus);
// accessing bus variables part 2: connecting reader with component of interest
connect(read1.y, gain1.u);
end TestBusConnectors;
end BusAdapters;
Graphically this will look something like below. x is written directly using the bus adapters. For y real expressions are used, to reduce the number of lines in larger models.
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.
I have written a code in Modelica to train a feedforward two-layer neural network for my Master thesis. The code receives a vector of six elements (u[nin]) and provides an output vector of two elements y[nout]. When I translate the code in dymola, I receive an error saying that the dimensionality of the parts included in a specific line of code must be equal. Once I remove this particular line, the code is translated successfully. I really spent much effort trying to resolve this error but in vain! Any help regarding the problem would be very much appreciated.
The code can be found below: (Please note that the line which causes the generation of the translation error is marked with // in the code).
model NN_block
Modelica.Blocks.Interfaces.RealInput
u[nin] "Connector of Real input signals"
annotation (Placement(transformation(extent={{-140,-20},{-100,20}},
rotation=0)));
Modelica.Blocks.Interfaces.RealOutput y[nout]
annotation (Placement(transformation(extent={{100,-10},{120,10}})));
parameter Integer nin2=1;
parameter Integer nin=6;
parameter Integer nout=2;
Real wji[10,6];
Real delta_wij[6,10];
Real bj[10,1];
Real delta_bjT[1,10];
Real wkj[2,10];
Real delta_wjk[10,2];
Real bk[2,1];
Real delta_bkT[1,2];
Real E;
Real ek[1,2];
Real yj[10,1];
Modelica.Blocks.Interfaces.BooleanOutput Input_trigger
annotation (Placement(
transformation(extent={{100,-46},{120,-26}}), iconTransformation(extent=
{{100,-46},{120,-26}})));
Modelica.Blocks.Interfaces.RealInput eTau1 annotation (Placement(
transformation(extent={{-182,36},{-142,76}}), iconTransformation(
extent={{10,-10},{-10,10}},
rotation=90,
origin={-44,90})));
Modelica.Blocks.Interfaces.RealInput eTau2 annotation (Placement(
transformation(extent={{-148,46},{-108,86}}), iconTransformation(
extent={{10,-10},{-10,10}},
rotation=90,
origin={50,90})));
annotation (Placement(transformation(extent={{-10,-10},{10,10}},
rotation=-90,
origin={-50,90}), iconTransformation(
extent={{-10,-10},{10,10}},
rotation=-90,
origin={0,90})));
algorithm
E:=1;
wji:=0.5*ones(10,6);
bj:=0.25*ones(10,1);
wkj:=0.75*ones(2,10);
bk:=0.6*ones(2,1);
delta_wij:=zeros(6,10);
delta_bjT:=zeros(1,10);
delta_wjk:=zeros(10,2);
delta_bkT:=zeros(1,2);
while E>0.01 loop
Input_trigger:=true;
y:=wkj*NeuralNetwork.Utilities.LogSig(wji*u+bj[:,1])+bk[:,1];
yj[:,1]:=NeuralNetwork.Utilities.LogSig(wji*u+bj[:,1]);
ek:=[eTau1,eTau2];
E:=0.5*(eTau1^2+eTau2^2);
if E>0.01 then
// delta_wij:=0.01*u*transpose(yj)*(ones(10,1)-yj)*ek*wkj+0.9*delta_wij;
delta_bjT:=0.01*transpose(yj)*(ones(10,1)-yj)*ek*wkj + 0.9*delta_bjT;
delta_wjk:=0.01*yj*ek + 0.9*delta_wjk;
delta_bkT:=0.01*ek + 0.9*delta_bkT;
wji:=wji+transpose(delta_wij);
bj:=bj+transpose(delta_bjT);
wkj:=wkj+transpose(delta_wjk);
bk:=bk+transpose(delta_bkT);
else
break;
end if;
end while;
annotation (Placement(transformation(extent={{-140,44},{-100,84}})),
uses(Modelica(version="3.2")), Icon(graphics={Rectangle(
extent={{-100,-100},{100,80}},
lineColor={0,0,255},
lineThickness=1), Text(
extent={{-68,20},{78,-16}},
lineColor={0,0,255},
lineThickness=1,
textString="Two-LayerNeural Network")}),
Diagram(graphics));
end NN_block;
Once I remove the lines using LogSig I could get OpenModelica to produce an error-message for you:
[a.mo:59:3-59:71] Error: Incompatible argument types to operation matrix multiplication, left type: Real[6], right type: Real[1, 10]
[a.mo:59:3-59:71] Error: Cannot resolve type of expression 0.01 * u * transpose(yj). The operands have types Real[6], Real[1, 10] in component .
u and yj' have dimensions 6 and 1,10
Looking at the code, it appears that there is mismatch in the sizes of the matrices on the right hand side of the equation concerned.
Try defining u as a 2D matrix of size 6x1.
Have you tested this line in the command line? This could be done by creating the variables used in your model in the workspace and then running the commented out line in the command line to check the sizing is correct. You can do this in the Dymola command line but I am not familiar enough with OpenModelica to tell if you can perform the same check there.
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