Could I define new variables in the Modelica script? - modelica

I am trying to run a Modelica script in Dymola, but I got an error when defining a variable in the script, as shown below:
Modelica.SIunits.Distance testData=2;
Boolean success;
success := clearlog();
Modelica.Utilities.Streams.print("Simulation result was:");
Modelica.Utilities.Streams.print("Distance = " + String(testData) + " m");
My question is:
Could I define new variables in the Modelica script?
I didn't find any regulation or chapter about the Modelica script file in the Modelica Specification 3.4, is there any reference material for Modelica script file specification?

Dymola just declares new variables based on assignments to the entire variable.
It should work for Real, Integer, Boolean, String, arrays and records.
However, it must be an assignment to the entire variable - so v[1]:=2; doesn't generate a vector.

Related

How to build a temp structt variable in s-function builder?

I meet a problem in the s function builder, I have to use a temp structure variable to transport the inputs to the extended C function.
Background: csolve function is a quadratic programming solver generated by CVXGEN for my QP problem, and I have tested the function in level-2 matlab s-fun. Now I want to use s function builder to genetate the TLC file that support the embedded code generate.
My Problem:
1) I have to use a temp structure variable 'params' to the inputs to csolve function in the outputs panel, could you please help me to solve this problem?
2) I find that in cvxgen folder contains a header file contains 'tic' and 'toc' function, how to use these functions in s function builder?
params.Aeq=Aeq;
params.beq=beq;
params.Aineq=Aineq;
params.bineq=bineq;
params.Smat=Smat;
params.Wmat=Wmat;
params.alpha=alpha;
[vars, status] = csolve(params)
y0=vars.x;
converge=status.converge;
for the attached files please see here
First some background information that you should know:
Matlab and C work completely differently and use different kinds of data types. To call C code from Matlab, so called "mex-functions" are generated. Matlab uses a special data type named mxArray to exchange data between Matlab and these "mex-functions", which are written in C.
In the C program an element (for example a variable) of the type mxArray represents a Matlab value of any data type. Matlab provides some functions (like mxGetData()) to access the actual data of the Matlab data element from the C function: There is some function for checking if the mxArray represents a floating-point value or a string. Another function allows you to convert the value from mxArray to double if the element has a floating-point value.
[vars, status] = csolve(params)
This means you want to call a "mex-function" from an "S-function".
Theoretically, this is possible but it is not as easy as you think:
First of all, the entry point of both types of functions is named mexFunction() in the C code. This means you cannot simply combine the C codes of both functions because in this case you would have two functions with the same name (mexFunction) in your S-function.
You might call the function mexCallMATLAB; however Mathworks writes that this function should not be called from S-functions.
The other possibility would be loading the mex-function using DLL functions (in Windows: LoadLibrary, GetProcAddress, FreeLibrary) and call the function mexFunction() of the mex-function using a function pointer.
However, in this case you have to convert all C data types to mxArray data and the data returned from the mex-function must be converted back ...
... a TLC file that is needed in ... embedded coder
The functions that access data of the mxArray type are only available when Matlab is running.
If you generate code that shall be executable outside Matlab, you cannot use mxArray and therefore you cannot call mex-functions.
The file csolve.c defines four structure variables:
Vars vars;
Params params;
Workspace work;
Settings settings;
And what the file actually does is the following:
Read the structure params (mxArray data type), convert these content to C data types and write the data into the four structure variables above
Call the following code:
steps = solve();
for (i = 0; i < extra_solves; i++)
solve();
The function solve() is defined in the other .c files in the project.
Take the values from the four structure variables and the value step returned by solve() and convert the data to mxArray.
Return the result as [vars, status]
You can define the four variables in your S-function code, fill these structures the same way the file csolve.c does it, call the solve() function as it is shown above and read the data of vars and status directly from the four variables.
You remove csolve.c from your project and add the other .c files of your mex-function to the S-function.

Extract Types/Classnames from flat Modelica code

I was wondering if there already exists a possibility to extract from flat Modelica code all variables AND their corresponding types (classnames respectively).
For example:
Given an extract from a flattened Modelica model:
constant Integer nSurfaces = 8;
constant Integer construction1.nLayers(min = 1.0) = 2 "Number of layers of the construction";
parameter Modelica.SIunits.Length construction1.thickness[construction1.nLayers]= {0.2, 0.1} "Thickness of each construction layer";
Here, the wanted output would be something like:
nSurfaces, Integer, constant;
construction1.nLayers, Integer, constant;
construction1.thickness[construction1.nLayers], Modelica.SIunits.Length, parameter
Ideally, for construction1.thickness there would be two lines (=number of construction1.nLayers).
I know, that it is possible to get a list of used variables from the dsin.txt, which is produced while translating a model. But until now I did not find an already existing way to get the corresponding types. And I really would like to avoid writing an own parser :-).
You could try to generate the file modelDescription.xml as defined by the FMI standard. It contains a ton of information and XML should be easier to parse, e.g. python has a couple of xml parsing/reading packages.
If you are using Dymola you just set the flag Advanced.FMI.GenerateModelDescriptionInterface2 = true to generate the model description file.
The second idea could be to let the compiler/tool parse the Modelica file for you as they need to do that anyway, try searching for AST (abstract syntax tree). In Dymola, this is available through the ModelManagement library, and also through the Python interface.
Third idea could be to use one of the Modelica parsers available, e.g. have a look at:
https://github.com/lbl-srg/modelica-json
https://hackage.haskell.org/package/modelicaparser
https://github.com/xie-dongping/modparc
https://github.com/pymoca/pymoca
https://github.com/pymola/pymola/tree/master/src/pymola
Fourth, if all that did not work, you still do not have to write a full parser, you could use ANTLR, then use an existing grammar file (look for e.g. modelica.g4).

Avoiding eval in matlab function

I use the symbolic toolbox in matlab to generate some very long symbolic expressions. Then I use matlabFunction to generate a function file.
Say there are three parameters: p1, p2 and p3.
I have a cell with strings {'p1', 'p2', 'p3'}.
In the derivation of the model I generate symbolic variables p1, p2 and p3 out of them using eval in a loop and stack them in a vector par.
Then when in matlabFunction, I specify par as input.
Moreover, I save the cell string in a .mat file.
Then when I want to simulate this model, I can construct this parameter array using that cell of strings from the .mat file out of 30 available parameters and their values.
Advantages: No need to keep track of the different parameters if I add one to . I can change the order, mess around, but older models still work.
Disadvantage:
Turning things into a function file leads to this error (psi is one of the parameters):
Error: File: f_derive_model.m Line: 96 Column: 5
"psi" previously appeared to be used as a function or
command, conflicting with its use here as the name of a
variable.
A possible cause of this error is that you forgot to
initialize the variable, or you have initialized it
implicitly using load or eval.
Apparently some unnescescary checking is going on because the variable will be intialized in an eval statement.
Question: How can I avoid eval but keep the list of parameters indepent from the model stuff.
Code deriving the long equations:
% Model parameters
mdl.parameters = {'mp','mb','lp','lb','g','d','mP','mM','k','kt'};
par = [];
for i=1:length(mdl.parameters)
eval(strcat(mdl.parameters{i}, '=sym(''', mdl.parameters{i}, "');"));
eval(sprintf(['par = [par;' mdl.parameters{i} '];']));
end
%% Calculate stuff
matlabFunction(MM,'file',[modelName '_mass'],'vars',{par},'outputs',{'M'});
Code using the generated file:
getparams
load('m3d_1')
par = [];
for i=1:length(mdl.parameters)
eval(sprintf(['par = [par;params.' mdl.parameters{i} '];']));
end
See how, as long as I specify the correct value to for example params.mp, it always gets assigned to the input corresponding to the symbolic variable mp in the par vector. I do not want to lose that and have to keep track of the order and so on, nor do I want to call my functions with all the parameters one by one.
Actually, I see nothing wrong in your approach even if the "public opinion" affirms that it's better to avoid using the eval function. An alternative would be using the assignin function as follows:
% use 'caller' instead of 'base' if this code runs within a function
for i = 1:numel(mdl.parameters)
var_name = mdl.parameters{i};
assignin('base',var_name,sym(var_name));
end
In the second case (the one concerning the par variable) I would instead use the getfield function:
par_len = numel(mdl.parameters);
par = cell(par_len,1);
for i = 1:par_len
par{i} = getfield(params,mdl.parameters{i});
end
or, alternatively, this approach:
par_len = numel(mdl.parameters);
par = cell(par_len,1);
for i = 1:par_len
par{i} = params.(mdl.parameters{i});
end

handing string to MATLAB function in Simulink

In my Simulink Model I have a MATLAB function, this_function, which uses as one parameter the name of the Simulink Model, modelname. The name is defined in an extra parameter file with all other parameters needed. Loading the parameter file loads modelname into the workspace. The problem is now, that this_function can't access modelname in the workspace and therefore the model doesn't run.
I tried to use modelname as a constant input source for this_function, which I used as a work-around previously, but Simulink doesn't accept chars/strings as signals. Furthermore does setting modelname to global not work as well.
Is there a way to keep modelname in the parameter file instead of writing it directly into this_function?
Simulink does not support strings. Like, anywhere. It really sucks and I don't know why this limitation exists - it seems like a pretty horrible design choice to me.
I've found the following workarounds for this limitation:
Dirty Casting
Let
function yourFun(num_param1, num_param2, ..., str_param);
be your MATLAB function inside the Simulink block, with str_param the parameter you want to be a string, and num_param[X] any other parameters. Then pass the string signal to the function like so:
yourFun(3, [4 5], ..., 'the_string'+0);
Note that '+0' at the end; that is shorthand for casting a string to an array of integers, corresponding to the ASCII codes of each character in the string. Then, inside the function, you could get the string back by doing the inverse:
model = char(str_param);
but usually that results in problems later on (strcmp not supported, upper/lower not supported, etc.). So, you could do string comparisons (and similar operations) in a similar fashion:
isequal(str_param, 'comparison'+0);
This has all the benefits of strings, without actually using strings.
Of course, the '+0' trick can be used inside constant blocks as well, model callbacks to convert workspace variables on preLoad, etc.
Note that support for variable size arrays must be enabled in the MATLAB function.
Fixed Option Set
Instead of passing in a string, you can pass a numeric scalar, which corresponds to a selection in a list of fixed, hardcoded options:
function yourFun(..., option)
...
switch (option)
case 1
model = 'model_idealised';
case 2
model = 'model_with_drag';
case 3
model = 'model_fullscale';
otherwise
error('Invalid option.');
end
...
end
Both alternatives are not ideal, both are contrived, and both are prone to error and/or have reusability and scalability problems. It's pretty hopeless.
Simulink should start supporting strings natively, I mean, come on.

how single and double type variables work in the same copy of code in Matlab like template in C++

I am writing a signal processing program using matlab. I know there are two types of float-pointing variables, single and double. Considering the memory usage, I want my code to work with only single type variable when the system's memory is not large, while it can also be adapted to work with double type variables when necessary, without significant modification (simple and light modification before running is OK, i.e., I don't need runtime-check technique). I know this can be done by macro in C and by template in C++. I don't find practical techniques which can do this in matlab. Do you have any experience with this?
I have a simple idea that I define a global string containing "single" or "double", then I pass this string to any memory allocation method called in my code to indicate what type I need. I think this can work, I just want to know which technique you guys use and is widely accepted.
I cannot see how a template would help here. The type of c++ templates are still determined in compile time (std::vector vec ...). Also note that Matlab defines all variables as double by default unless something else is stated. You basically want runtime checks for your code. I can think of one solution as using a function with a persistent variable. The variable is set once per run. When you generate variables you would then have to generate all variables you want to have as float through this function. This will slow down assignment though, since you have to call a function to assign variables.
This example is somehow an implementation of the singleton pattern (but not exactly). The persistent variable type is set at the first use and cannot change later in the program (assuming that you do not do anything stupid as clearing the variable explicitly). I would recommend to go for hardcoding single in case performance is an issue, instead of having runtime checks or assignment functions or classes or what you can come up with.
function c = assignFloat(a,b)
persistent type;
if (isempty(type) & nargin==2)
type = b;
elseif (isempty(type))
type = 'single';
% elseif(nargin==2), error('Do not set twice!') % Optional code, imo unnecessary.
end
if (strcmp(type,'single'))
c = single(a);
return;
end
c = double(a);
end