Modelica: Mixing connectors and direct inputs - modelica

The following Modelica package - while neither being particularly useful nor interesting - does not yield any warnings.
package P
connector C
Real c;
end C;
model A
input C x;
output Real y;
equation
y = x.c;
end A;
model B
input C inp;
output C out;
A a;
equation
a.x = inp;
out.c = a.y;
end B;
end P;
However, when A does not use connectors as in the following case, there is a warning: The following input lacks a binding equation: a.x. Clearly, there is a binding equation for a.x. Why is there such a warning?
package P
connector C
Real c;
end C;
model A
input Real x;
output Real y;
equation
y = x;
end A;
model B
input C inp;
output C out;
A a;
equation
a.x = inp.c;
out.c = a.y;
end B;
end P;

The issue here is that there is not a binding equation. There is only an ordinary equation. A binding equation is one that is applied as a modification to the element, e.g.
model B
input C inp;
output C out;
A a(x=inp.c) "Binding equation";
equation
out.c = a.y;
end B;
Note that in general, if two things are connectors, they should not be equated, they should be connected. That will help you avoid this issue. So in your first version of B:
model B
input C inp;
output C out;
A a;
equation
connect(a.x, inp);
out.c = a.y;
end B;
The reason for the binding equation restriction has to do with making sure components are balanced. You can read more about that in the specification or in Modelica by Example. By using it as a binding equation, it makes it clear that this equation can be used to solve for this variable (i.e., the term in the equation containing that variable won't vanish or be ill-conditioned).

Related

Continuous variable used in clocked when clause is automatically discretized

model test
import Modelica.Constants.pi;
Real f;
discrete Real g;
Clock clk=Clock(0.1);
equation
f = sin(pi*time);
when Clock(0.1) then
if f >= 0 then
g = (sin(pi*time)) - 0.1;
else
g = (sin(pi*time)) + 0.1;
end if;
end when;
end test;
f is assigned as a continuous function. I want to sample the value of g depended on f, but f also be changed to a discrete value. Is there anything wrong ?
The clock partitioning sees f as being used directly inside the when Clock and thus f is also seen as a clocked variable.
Use sample(f) if that is not desired:
model test
import Modelica.Constants.pi;
Real f;
discrete Real g;
Clock clk=Clock(0.1);
equation
f = sin(pi*time);
when Clock(0.1) then
if sample(f) >= 0 then
g = (sin(pi*time)) - 0.1;
else
g = (sin(pi*time)) + 0.1;
end if;
end when;
end test;
See also: Failure to handle clock inference in Dymola

Redeclare model with "outer" parameters

I tried redeclare model that contain global (outer) parameter. Here simple example of my code:
package tests
model M0
inner parameter Real a = 1;
end M0;
model M1
extends tests.M0;
replaceable tests.M3 c;
end M1;
model M2
outer constant Real a;
end M2;
model M3
extends tests.M2;
Real b;
equation
b = a;
end M3;
model M4
extends tests.M2;
Real b2;
equation
b2 = a;
end M4;
model test1
tests.M1 X;
end test1;
model test2
tests.M1 X(redeclare each tests.M4 c);
end test2;
end tests;
Test1 works fine, but with test2 I have warning An inner declaration for outer component a could not be found and was automatically generated.
Without "inner/outer" all works fine.
The warning occurs even if M3 and model M4 have identically code
model M3 // and M4
outer constant Real a;
Real b;
equation
b = a;
end M3;
or if redeclare the same model
model test3
tests.M1 X(redeclare tests.M3 c);
end test3;
I am using OM 1.18
The issue seems to be that b is defined in M3 but not in M4. Modifying M4 to
model M4
extends tests.M2;
Real b, b2;
equation
b = a;
b2 = a;
end M4;
or
model M4
extends tests.M2;
Real b;
equation
b = a;
end M4;
removes the respective warnings in Dymola.
This comes down to plug-compatibility, which in this example means, that every public variable in M3 must be present in M4 as well.
As plug-compatibility only refers to public variables, defining b to be protected in M3 should also resolve the issue:
model M3
extends tests.M2;
protected
Real b;
equation
b = a;
end M3;
Note: I didn't test it with OpenModelica...
Your code works in Dymola, even though there is one issue:
In M0 you declared a as a parameter
inner parameter Real a = 1;
But in M2 you are looking for a constant
outer constant Real a;
Both tools don't care much about that fact, which seems strange.
In OpenModelica I guess you have hit a bug. You are using inner/outer in an uncommon way. Changing your setup to a more common style with the inner variable defined in a top-level-component (now named World) works:
package tests
model World
inner parameter Real a = 1;
end World;
model M1
replaceable tests.M3 c;
end M1;
model M2
outer World w;
parameter Real a = w.a;
end M2;
model M3
extends tests.M2;
Real b;
equation
b = a;
end M3;
model M4
extends tests.M2;
Real b2;
equation
b2 = a;
end M4;
model test1
inner World w;
tests.M1 X;
end test1;
model test2
inner World w;
tests.M1 X(redeclare each tests.M4 c);
end test2;
end tests;

Modelica coding standards / new OpenModelica compiler frontend

looks like a issue with new OpenModelica compiler frontend. I am using official release version of openmodelica 1.14 on windows-7 64bit OS.
package Test1_14
model M1
parameter Integer size = 2 "matrix size";
parameter Real A[size] = {1.0, 1.0};
Real B[size];
Real T = 1;
Real P = 2;
equation
B = A * (T/P);
end M1;
model M1_Extn
Real C[size];
Real D[size];
equation
for J in 1:size loop
C[J] = Func1(T);
D[J] = C[J] / P;
end for;
end M1_Extn;
function Func1
input Real a;
output Real b;
algorithm
b := a*a;
end Func1;
model M1_Combined
parameter Integer size = 2 "matrix size";
Real B[size];
Real T = 1;
Real P = 2;
extends M1_Extn;
equation
B = D;
end M1_Combined;
end Test1_14;
When I compile the model ‘M1_Combined’, the code generation fails with new OpenModelica compiler frontend. Export FMU also fails with the same error.
Is my code as per Modelica programing standards?
How do I declare variables - size, T, P in the model M1_Extn and still use keyword ‘extends’ in ‘M1_Combined’ ?
This is because the old frontend did not handle the "extends" correctly, according to the Modelica Specification. The new frontend does it correctly.
To be clear, you cannot define a variable in this class and then use it in the extends any other way than via a modification (and via inner/outer, via redeclare as element). An example is below, you cannot use a inside M1.
package TestExtends
model M1
parameter Real b = a;
end M1;
model M2
parameter Real a = 1;
extends M1;
end M2;
end TestExtends;
To fix your model so that is according to Modelica standards, you can do:
package Test1_14
model M1
parameter Integer size = 2 "matrix size";
parameter Real A[size] = {1.0, 1.0};
Real B[size];
Real T = 1;
Real P = 2;
equation
B = A * (T/P);
end M1;
model M1_Extn
parameter Integer size = 2;
Real T = 1;
Real P = 2;
Real C[size];
Real D[size];
equation
for J in 1:size loop
C[J] = Func1(T);
D[J] = C[J] / P;
end for;
end M1_Extn;
function Func1
input Real a;
output Real b;
algorithm
b := a*a;
end Func1;
model M1_Combined
extends M1_Extn(size=2, T = 1, P = 2);
Real B[size]; // this one works as you can use things defined in extends.
equation
B = D;
end M1_Combined;
end Test1_14;

Modeling skewed delay for combinational logic

I need help to model a block with different delays for various input-output paths?
input A;
input [3:0] B, C;
output [3:0] Y;
Y = B xor C if A = 1 else Y = 0
with A->Y delay of 10us when posedge A (rise delay) and 5us when negedge A(fall delay)
and B,C - > Y delay is 1us (applicable only if A = 1)
For my case, I might need to use procedural way and assign statements might not suit.
Here is something that worked best for me.
`timescale 1us/1ns
module xor_w_enabled(input A, input B, input C, output Y);
wire A_delayed;
wire B_xor_C_delayed;
assign #1 B_xor_C_delayed = B^C;
assign #(10,5) A_delayed = A;
assign Y = (A_delayed == 1) ? B_xor_C_delayed : 0;
endmodule
Please let me know if I'm missing anything.
For non-synthesizable models you can use #delay constructs combined with `timescale to model delays. something like the following code
`timescale 1us/1us
module delayModule(A,B,C,Y);
input A;
input [3:0] B, C; // this should probably be output
output [3:0] Y;
reg [3:0] tmpb, tmpy;
always #(posedge A)
#10us tmpb <= 1;
always #(negedge A)
#5us tmpb <= 0;
always #* begin
if (A == 1)
#1us tmpy =(B^C);
end
assign B = tmpb;
assign Y = tmpy;
endmodule // delayModule

Undefined function or variable

I have a simple function as below:
function dz = statespace(t,z)
dz = A*z + B*k*z
end
My main script is :
clear all;close all;format short;clc;
% step 1 -- input system parameters
% structure data
M1 = 1; M2= 1; M3= 1; %Lumped Mass(Tons)
M= diag([M1,M2,M3]);
k(1)= 980; k(2)= 980; k(3)= 980; %Stiffness Coefficient(KN/M)
K = zeros(3,3);
for i=1:2
K(i,i)=k(i)+k(i+1);
end
K(3,3)=k(3);
for i=1:2
K(i,i+1)=-k(i+1);
end
for i=2:3
K(i,i-1)=-k(i);
end %Stiffness Matrix(KN/M)
c(1)= 1.407; c(2)= 1.407; c(3)= 1.407; %Damping Coefficient(KN.sec/M)
C = zeros(3,3);
for i=1:2
C(i,i)=c(i)+c(i+1);
end
C(3,3)=c(3);
for i=1:2
C(i,i+1)=-c(i+1);
end
for i=2:3
C(i,i-1)=-c(i);
end %Damping Matrix(KN.sec/M)
A = [zeros(3) eye(3);-inv(M)*K -inv(M)*C]
H = [1;0;0]
B = [0;0;0;inv(M)*H]
k = [-1 -1 -1 -1 -1 -1]
t = 0:0.004:10;
[t,z] = ode45(statespace,t);
When I run my main script it comes with following error:
Undefined function or variable 'A'.
Error in statespace (line 2)
dz = A*z + B*k*z
As you can see I defined A in main script. Why this problem happening?
There multiple things wrong with your code. First, you need to supply the values of A and B to your function but as you are invoking it (incorrectly without the # and additional parameter y0 as I commented below) in the toolbox ode45, you have to keep just two parameters so you cannot supply A and B as additional parameters. If you define A and B within your function or share them via global variables you will get further. However, as noted below the definitions don't seem to be correct as A * z and B * k * z don't have the same dimensions. z is a scalar so B * k needs to be same size and shape as A which currently it is not.
Edit from:
As Jubobs suggested change your function's parameters to include A, B and k. Also you don't need t as it is never used in the function. So:
function dz = statespace(A, B, k, z)
dz = A*z + B*k*z
end
As others have pointed out, A, B and k are not defined in the function workspace, so you either need to define them again (ugly, not recommended), declare them as global variables (slightly better, but still not good practice), or pass them as arguments to your function (the better solution). However, because you then want to use the function with ode45, you need to be a bit careful with how you do it:
function dz = statespace(t,z,A,B,k)
dz = A*z + B*k*z
end
and then the call to ode45 would like this:
[t,z] = ode45(#(t,z)statespace(t,z,A,B,k),[0 Tf],z0); % where Tf is your final time and z0 your initial conditions
See Error using ode45 and deval for a similar problem.