I created a model in OpenModelica and would like to create a FMU from it.
Inside OpenModelica, I can initialize the parameters the following:
model r_ctrl
parameter Real startTime(start = 0.1);
parameter SI.Resistance u_ref(start = 230);
parameter SI.Power p_ref(start = 1000);
parameter Real r_start(start = u_ref*u_ref/p_ref);
...
This works without any problems, during the simulation, all parameters have the values they are supposed to have
When I create the FMU, the following error appears in the terminal:
[CodegenUtil.tpl:178:14-178:14:writable] Error: Template Fehler: initial value of unknown type: r_ctrl.u_ref ^ 2.0 / r_ctrl.p_ref.
Is there a way to set the parameters dependent of each other, but without getting errors in the FMU generation process?
The following should work (I suppose the above should as well, but requires OpenModelica to automatically translate it into something like the following):
model r_ctrl
parameter Real startTime = 0.1;
parameter SI.Resistance u_ref = 230;
parameter SI.Power p_ref = 1000;
parameter Real r_start(fixed=false);
initial equation
r_start = u_ref*u_ref/p_ref;
Related
I have a mex-function specialRationalMap_00001.mexw64, that can be called without problems
vm = specialRationalMap_00001(vm,amplitude);
If I am trying to use the function name and str2func
f_str = 'specialRationalMap_00001';
fz = str2func(strcat('#(vm,amplitude)', f_str));
vm = fz(vm,amplitude);
I got the error: "A map input and a (scalar) amplitude required", but I am using exactly this as input.
Dont forget to actually pass the input arguments. Either do
fz = str2func(strcat('#(vm,amplitude)', f_str, '(vm,amplitude)'));
But better, you can just do:
fz = str2func(f_str);
So in one of the mask in the model i came across an initialization command that i don't understand.
The logic is for an SR Flip Flop. That latches the output.
It has 1 parameter that takes in the initial state for output 1(Output is o and o(bar)).
Which has the following properties:
Name: MaskParam1
Value: 0
Type: Edit
Evaluate: True
Tunable: True
The command is written in the Initialization tab of the Mask Editor.
ini = (#1~=0);
The first thing that came to my mind was anonymous function handle, that returns value of the parameter. In this case would be 0.
So as (0 ~=0) = 0hence the initial output of SR will be 0.
When i type the following in matlab:
ini = (#1~=0);
I get an error of unexpected matlab expression.
So I tried another thing. Considering as the Parameter is refering to the masked parameter so if we take a variable:
x = 0;
% The default value for the mask parameter
ini = (#x~=0);
This will give an error that
Error: "x" was previously used as a variable, conflicting with its use here as the name of a function or command.
So my question is ini
ini = (#1~=0)
a function or a variable??enter code here
I am new to matlab and am trying to compile legacy matlab code into C. I come across the following error when doing so:
??? The left-hand side has been constrained to be non-complex, but the
right-hand side is complex. To correct this problem, make the
right-hand side real using the function REAL, or change the initial
assignment to the left-hand side variable to be a complex value using
the COMPLEX function.
The code that it complains on is in the comments of the code below:
function [z_out,ovf_flag,ovf_cnt] = fxpt_sgn_saturate(z_in,Nb_out)
Nb_out=(Nb_out<=0)+(Nb_out>0)*Nb_out;
max_val = 2^(Nb_out-1)-1;
min_val = -2^(Nb_out-1);
ovf_cnt = 0;
tmp_ind = find(real(z_in) > max_val);
z_in(tmp_ind) = max_val+1j*imag(z_in(tmp_ind)); // ERROR OCCURS HERE
ovf_cnt = ovf_cnt + numel(tmp_ind);
tmp_ind = find(real(z_in) < min_val);
z_in(tmp_ind) = min_val+1j*imag(z_in(tmp_ind));
ovf_cnt = ovf_cnt + numel(tmp_ind);
tmp_ind = find(imag(z_in) > max_val);
z_in(tmp_ind) = real(z_in(tmp_ind))+1j*max_val;
ovf_cnt = ovf_cnt + numel(tmp_ind);
tmp_ind = find(imag(z_in) < min_val);
z_in(tmp_ind) = real(z_in(tmp_ind))+1j*min_val;
ovf_cnt = ovf_cnt + numel(tmp_ind);
z_out = z_in;
ovf_flag = ~(ovf_cnt==0);
return
I don't particularly understand the code well. Any ideas how to fix this issue?
Thanks
When generating the code, you can use the -args flag to specify the size, class, and complexity of your input arguments. You can explicitly cast z_in as a complex number to ensure that the code generation succeeds.
codegen fxpt_sgn_saturate -args {complex(z_in), double(Nb_out)}
Alternately, if you're calling this function from within many other functions and are only calling codegen on the top-level function, then you'll want to explicitly cast the input as a complex datatype within your code prior to calling the function so that codegen can appropriately determine the complexity of the input.
function a(thing)
fxpt_sgn_saturate(complex(thing), 10);
end
I have developed a model for a configurable variable, meaning that the variable may be defined by a parameter, specified via a real input, or left undefined so that it can be solved for.
model ConfigurableReal
"Configurable variable that can be set by parameter, by real input, or left undetermined"
parameter Boolean isSpecifiedByParameter = false
"true if value is specified by paramter"
annotation(Dialog(group="Specify by Parameter", enable = not isSpecifiedByInput));
parameter Boolean isSpecifiedByInput = false
"true if value is specified by real input"
annotation(Dialog(group = "Specify by Real Input", enable=not isSpecifiedByParameter));
parameter Real specifiedValue(unit=unitString) = 0
"specified value to use if isSpecifiedByParameter == true"
annotation(Dialog(group="Specify by Parameter", enable = isSpecifiedByParameter));
// Conditionally declare the realInput
Modelica.Blocks.Interfaces.RealInput realInput if isSpecifiedByInput
annotation (Placement(transformation(extent={{-140,-20},{-100,20}})));
Real value "active value";
protected
Modelica.Blocks.Sources.Constant constantBlock(final k = specifiedValue) if isSpecifiedByParameter
"constant block to hold specified input";
Modelica.Blocks.Interfaces.RealInput value_ "connected value";
equation
value = value_;
// Connect the real input to the value if the real input exists
// This only happens if isSpecifiedByInput==true, because the RealInput is
// conditionally declared above
connect(realInput, value_);
// Connect the constant block to the value if the value is specified by parameter
// This only happens if isSpecifiedByParameter == true, because the Constant is
// conditionally declared above
connect(constantBlock.y, value_);
annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={
Rectangle(
extent={{-80,40},{80,-40}},
lineColor={28,108,200},
fillColor={255,255,255},
fillPattern=FillPattern.Solid),
Text(
extent={{-70,30},{70,-32}},
lineColor={28,108,200},
textString="Config
Variable"),
Text(
extent={{-100,80},{100,50}},
lineColor={28,108,200},
fillColor={255,255,255},
fillPattern=FillPattern.Solid,
textString=DynamicSelect("", "value = " + String(value, significantDigits=4))),
Text(
extent={{-100,-50},{100,-80}},
lineColor={28,108,200},
fillColor={255,255,255},
fillPattern=FillPattern.Solid,
textString="%name")}),
Diagram(
coordinateSystem(preserveAspectRatio=false)));
end ConfigurableReal;
Now I would like to extend the model in a way that leverages the quantity/unit types instead of only Reals. Is it possible to assign variable type via a parameter? For instance, is it possible to declare a variable as shown below?
parameter String variableType = "Pressure";
parameter typeOf(variableType) variableType;
If so, I could define the variable types in the ConfigurableReal model to reference the variableType object and write a configurable pressure model by:
model ConfigurablePressure extends ConfigurableReal(final variableType="Pressure");
If not, is there something in Modelica like C# Type Parameters?
In the end, I am really trying to find a way to extend my ConfigurableReal model so that it can be a ConfigurablePressure, ConfigurableTemperature, ConfigurableMassFlowRate,..., containing units in parameter inputs and simulation results without having to copy and paste the model code for each variable type and manually assign the variable types in each class.
Any help is greatly appreciated.
Thanks,
Justin
Justin, what you really want is to use redeclare + replaceable. You mention C# type parameters. Modelica does have something like that, but they don't quite look (syntactically) the same and they have some additional constraints because of the mathematical constraints of Modelica.
If you haven't already read the chapter on Architecture in my book, that will give you a start.
To complete the analogy to C# type parameters, consider this model:
model Circuit
replaceable Resistor R constrainedby Element;
...
end Circuit;
This says that R must have be a subtype of Element. By default, it is a Resistor, but you can change that. Note that Element and Resistor or both types. So you are changing the type of R by changing them. You change the with redeclare (see book).
In that case, the "type parameter" only applies to one variable, R. But you can do this in a more C# like way with:
model Circuit
replaceable model X = Resistor constrainedby Element;
X R1;
X R2;
}
In C#, this would be something like:
class Circuit<X> where X : Element {
X R1;
X R2;
}
(except that C# doesn't defaults as far as I can remember)
I have to run, but I hope that helps.
I am using PyOMO to model a semi-batch reaction.
Consider an ODE system that describes a semi-batch reactor where one of the reactants is fed at a given volume flow for t1 units of time, the reaction goes on until t end, and obviously t1 < t end.
To specify the stop in the flow, I can either use a conditional rule (assume t1 = 3.5*60):
def _vol_flow_in_schedule(mod,t):
if t<=3.5*60:
return mod.vol_flow_in[t] == (12.3/1000)/(3.5*60)
else:
return mod.vol_flow_in[t] == 0
m1.vol_flow_in_schedule = Constraint(m1.time,rule=_vol_flow_in_schedule)
which will create a discontinuity (and then my model does not converge). What I want to do is use a sigmoidal function that will transition the flow to zero without a discontinuity.
To implement the sigmoidal though I need to refer to the time variable itself.
The below MATLAB code gives me the result I want:
t=[0:1:500];
acc=2; %Acceleration parameter, higher values yields sharper change.
time_of_step=3.5*60;
init_value = (12.3/1000)/(3.5*60);
end_value = 0;
sigmoidal=(init_value+(end_value-init_value)/2)...
+((end_value-init_value)/2)*atan((t-time_of_step)*acc)/atan(max(t));
This implementation however needs the time variable explicitly in the function. How can I access the time variable inside the PyOMO rule? I tried the below, but I get an " Cannot treat the scalar component 't_of_step' as an array" error:
m1.init_value = Param(initialize = (12.3/1000)/(3.5*60))
m1.end_value = Param(initialize = 0)
m1.t_of_step = Param(initialize = 210)
m1.acc = Param(initialize = 5)
.
.
def _vol_flow_sigmoidal (mod,t):
return mod.vol_flow_in[t] == (mod.init_value+(mod.end_value-mod.init_value)/2)+((mod.end_value-mod.init_value)/2)*atan((t-mod.t_of_step)*mod.acc)/atan(1500)
m1.vol_flow_sigmoidal = Constraint(m1.time,rule=_vol_flow_sigmoidal)
Hopefully I've described clearlyt what I am after. Any hints are most welcome,
Thanks!
Sal
How are you declaring the m1.time index?
My guess is that you are using a NumPy array to initialize the m1.time index. There is a known problem in Pyomo (see Issue #31) where the NumPy operator overloading and the Pyomo operator overloading end up fighting with each other (basically, NumPy gets fooled into thinking Pyomo scalars are actually indexed and attempts to treat them like arrays).
I was able to reproduce the error with the following complete example:
# pyomo 4.4.1
from pyomo.environ import *
import numpy as np
m1 = ConcreteModel()
m1.time = Set(initialize=np.array([0,100,200,300,400,500]))
m1.vol_flow_in = Var(m1.time)
m1.init_value = Param(initialize = (12.3/1000)/(3.5*60))
m1.end_value = Param(initialize = 0)
m1.t_of_step = Param(initialize = 210)
m1.acc = Param(initialize = 5)
def _vol_flow_sigmoidal (mod,t):
return mod.vol_flow_in[t] == (mod.init_value+(mod.end_value-mod.init_value)/2)\
+((mod.end_value-mod.init_value)/2)*atan((t-mod.t_of_step)*mod.acc)/atan(1500)
m1.vol_flow_sigmoidal = Constraint(m1.time,rule=_vol_flow_sigmoidal)
There are two alternatives that do work, both based on avoiding using NumPy arrays to initialize Pyomo Sets. You can either completely avoid Numpy:
m1.time = Set(initialize=[0,100,200,300,400,500])
or explicitly cast the NumPy array to a list:
timeArray = np.array([0,100,200,300,400,500])
m1.time = Set(initialize=timeArray.tolist())
Finally, for completeness, two other notes:
This also applies to initializing ContinuousSet objects in pyomo.dae
You will see the same behavior even if you avoid the explicit Pyomo Set declaration. That is, the following will also generate the error:
m1.time = np.array([0,100,200,300,400,500])
# ...
m1.vol_flow_sigmoidal = Constraint(m1.time,rule=_vol_flow_sigmoidal)
This is because Pyomo will quietly create the Set object for you behind the scenes as m1.vol_flow_sibmodial_index and then use that Set to index the Constraint.