OpenModelica: How to create a custom periodic voltage source? - modelica

I'm using OpenModelica 1.19.2 on Ubuntu 20.04, and I was wondering how I can create a custom periodic voltage source, with values read from an external file.
I noticed that there's the option of a TableVoltage, which takes a two-column table as input, and uses linear interpolation/extrapolation. I was hoping that this might have similar possibilities as CombiTable1D, in that you can specify a file name and extrapolation options, but that doesn't work.
Is there some way to achieve this behaviour? For example, would it be possible to generate a table using CombiTable1D and use this as an input for TableVoltage? And if so, how would I go about that? As a first guess, I tried
Modelica.Blocks.Tables.CombiTable1D myTable(fileName = "inputFile.txt", extrapolation = 3);
Modelica.Electrical.Analog.Sources.TableVoltage myVoltage(table = myTable);
but apparently that's not the right way:
Translation Error: Dimension 1 of ‘table‘ could not be deduced from the component's binding equation myTable[<myVoltage, myVoltage>]).

Using the CombiTable is a good idea as it provides a lot of functionality related to inter-/extrapolation. But you cannot pass the table object (myTable) to TableVoltage. Instead, usually connections are created between the objects. This sets the output myTable.y to the desired value(*).
This is done in the following example, which you should be able to directly copy into your Modelica code editor:
model SignalSource
Modelica.Blocks.Sources.CombiTimeTable combiTimeTable(
tableOnFile=true,
tableName="voltage",
fileName="inputFile.txt",
extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic)
annotation (Placement(transformation(extent={{-60,-10},{-40,10}})));
Modelica.Electrical.Analog.Sources.SignalVoltage signalVoltage
annotation (Placement(transformation(extent={{10,-10},{-10,10}}, rotation=90)));
Modelica.Electrical.Analog.Basic.Ground ground annotation (Placement(transformation(extent={{30,-40},{50,-20}})));
Modelica.Electrical.Analog.Basic.Resistor resistor(R=10)
annotation (Placement(transformation(
extent={{-10,-10},{10,10}},
rotation=270,
origin={80,0})));
equation
connect(resistor.p, signalVoltage.p) annotation (Line(points={{80,10},{80,20},{0,20},{0,10}}, color={0,0,255}));
connect(signalVoltage.n, ground.p) annotation (Line(points={{0,-10},{0,-20},{40,-20}}, color={0,0,255}));
connect(ground.p, resistor.n) annotation (Line(points={{40,-20},{80,-20},{80,-10}}, color={0,0,255}));
connect(combiTimeTable.y[1], signalVoltage.v)
annotation (Line(points={{-39,0},{-25.5,0},{-25.5,6.66134e-16},{-12,6.66134e-16}}, color={0,0,127}));
annotation (uses(Modelica(version="4.0.0")), experiment(StopTime=10));
end SignalSource;
If you then add a file inputFile.txt with the following content:
#1
double voltage(6,2)
0 0
1 0
1 1
2 4
3 9
4 16
to the working directory(**), the model should provide the following result:
(*): An alternative to having connect statements, for this example would be adding the equation signalVoltage.v = combiTimeTable.y[1];, but usually the graphical variant is preferred.
(**): As an alternative you can use any local path, but you need to specify it in the parameters of the combiTable.

Related

Split model Dymola

I'm having a problem when I use the "Split model" option. What I want to do is basically hide these 10 water volumes:.
I select the tanks then I click on button for splitting with these options:
Final result is just what I want:
When I check the entire model to verify if everything is ok, these errors come out:
I've tried several things such as modifying the text part of the splitted model with no positive results, here's the original NOT modified
Can you please explain to me what kind of error it is? How can I resolve it? Thank you.
Edit: I'm using TIL library
Edit after Markus' answer: in the split model is it necessary to declare the type of liquid and change the portArray definition. I copied these lines of code and everything worked!
parameter TILMedia.LiquidTypes.BaseLiquid liquidType = sim.liquidType1
"Liquid type" annotation (Dialog(tab="SIM",group="SIM"),choices(
choice=sim.liquidType1 "Liquid 1 as defined in SIM",
choice=sim.liquidType2 "Liquid 2 as defined in SIM",
choice=sim.liquidType3 "Liquid 3 as defined in SIM"));
replaceable package MediaConfiguration =
TIL.Utilities.MediaConfiguration
constrainedby TIL.Utilities.Internals.PartialMediaConfiguration
"Media and State Type Configuration" annotation (choicesAllMatching, Dialog(
tab="SIM", group="Media Configuration"));
protected
outer TIL.SystemInformationManager sim "System information manager";
and
public
TIL.Connectors.LiquidPort portArray(
final liquidType=liquidType) ;
TIL.Connectors.LiquidPort portArray1(
final liquidType=liquidType) ;
The issue seems to result from the vectorization of the connectors, that seems to get lost when using "split model". A bit difficult without the actual model, but:
Have you tried to modify the last two connect statements in str3000 to:
connect(portArray, colume.portArray[1])
connect(portArray1, colume.portArray[2])
Additionally on the top level of the model, it seems you have connections to vectors of str3000.portArray. Try to remove them as they seem to be wrong, as you have two non-vector ports.
There should be something like connect(str3000.portArray[1], ...) and connect(str3000.portArray1[2], ...), which should likely be changed to connect(str3000.portArray, ...) and connect(str3000.portArray1, ...).

How to set the DynamicSelect expression in Modelica models

I plan to show a variable's quantity in a text string, so I checked the usage of DynamicSelect expression in Modelica Specification, as shown below:
Here is an example I make, it only contains one Modelica.Blocks.Sources.Sine component and a text label, but I am not sure why the text doesn't change during the simulation. It seems like the DynamicSelect expression doesn't work at all.
My question is:
How should I set the DynamicSelect expression to make it work?
model fsdaf
Modelica.Blocks.Sources.Sine sine(amplitude=100, freqHz=1)
annotation (Placement(transformation(extent={{-124,-10},{-104,10}})));
equation
annotation (Diagram(graphics={
Text(
extent={{-22,60},{98,10}},
lineColor={28,108,200},
fillColor={238,46,47},
fillPattern=FillPattern.None,
textString=DynamicSelect(10,string(sine.y)))}),
uses(Modelica(version="3.2.3")));
end fsdaf;
Please use String() for conversion of numeric values to string.
Browse the Modelica Standard Library which uses DynamicSelect in various places.
Here is an improved example for Modelica Standard Library version 4 with slowed down simulation:
model TestDynamicSelect
Modelica.Blocks.Sources.Sine sine(amplitude=100, f=1) annotation(Placement(transformation(extent={{-80,40},{-60,60}})));
Modelica_DeviceDrivers.Blocks.OperatingSystem.RealtimeSynchronize realtimeSynchronize annotation(Placement(transformation(extent={{-80,0},{-60,20}})));
annotation(experiment(StopTime=10), Diagram(graphics={
Text(
extent={{-22,60},{98,10}},
lineColor={28,108,200},
fillColor={238,46,47},
fillPattern=FillPattern.None,
textString=DynamicSelect(10,String(sine.y)))}),
uses(Modelica(version="4.0.0"), Modelica_DeviceDrivers(version="2.0.0")));
end TestDynamicSelect;

How do I create arbitrary parameterized layers in DiffEqFlux.lj neuralODE? Julia Julialang Flux.jl

I am able to create and optimize neuralODEs in julia(1.3 and 1.2) using Flux.jl and DiffEqFlux.jl but it fails under a crucial important general case.
what works:
I can train the Neural net parameters if it is built out of the
provided Flux.jl layers like Dense().
I can include an arbitrary function as a layer in the network chain, e.g. x -> x.*x
What fails:
However if the arbitrary function has parameters I want to train then Flux. Train will not adjust these parameters causing it to fail.
I have tried making these added parameters Tracked and included in the list of parameters given to the training system but it ignores them and they remain unvaried.
The documentation says very cryptically that one can use Flux.#functor on a layer to make sure it's parameters get tracked. However functor was not included in Flux till version 0.10.0 and the only version of Flux compatible with NeuralODEs in DiffEqFlux is 0.9.0
So here's an toy example of a 2 layer neural net I want to use
p = param([1.0])
dudt = chain( x -> p[1]*x.*x, Dense(2,2) )
ps = Flux.params(dudt)
then I use the flux train on this. when I do this the parameter p is not varied, but the parameters in the Dense layer are.
I have tried explicitly including like this
ps = Flux.Params([p,dudt])
but that has the same result and the same problem
I think what I need to do is build a struct with an associted function that implements the
x->p[1]*x*x
then call #functor on this. That struct can then be used in the chain.
But as I noted the version of Flux with #functor is not compatible with DiffEqFlux of any version.
So I need a way to make flux pay attention to my custom parameters, not just the ones in Dense()
How???
I think I get what your question is, but please clarify if I am answering the wrong question here. The issue is that the p is only grabbing from a global reference and thus not differentiated during adjoints. A much better way to handle this in 2020 is to use FastChain. The FastChan interface lets you define layer functions and their parameter dependencies, so this is a nice way to make your neural network incorporate arbitrary functions with parameters. Here's what that looks like:
using DifferentialEquations
using Flux, Zygote
using DiffEqFlux
x = Float32[2.; 0.]
p = Float32[2.0]
tspan = (0.0f0,1.0f0)
mylayer(x,p) = p[1]*x
DiffEqFlux.paramlength(::typeof(mylayer)) = 1
DiffEqFlux.initial_params(::typeof(mylayer)) = rand(Float32,1)
dudt = FastChain(FastDense(2,50,tanh),FastDense(50,2),mylayer)
p = DiffEqFlux.initial_params(dudt)
function f(u,p,t)
dudt(u,p)
end
ex_neural_ode(x,p) = solve(ODEProblem(f,x,tspan,p),Tsit5())
solve(ODEProblem(f,x,tspan,p),Tsit5())
du0,dp = Zygote.gradient((x,p)->sum(ex_neural_ode(x,p)),x,p)
where the last value of p is the one parameter for p in mylayer. Or you can directly use Flux:
using DifferentialEquations
using Flux, Zygote
using DiffEqFlux
x = Float32[2.; 0.]
p2 = Float32[2.0]
tspan = (0.0f0,1.0f0)
dudt = Chain(Dense(2,50,tanh),Dense(50,2))
p,re = Flux.destructure(dudt)
function f(u,p,t)
re(p[1:end-1])(u) |> x-> p[end]*x
end
ex_neural_ode() = solve(ODEProblem(f,x,tspan,[p;p2]),Tsit5())
grads = Zygote.gradient(()->sum(ex_neural_ode()),Flux.params(x,p,p2))
grads[x]
grads[p]
grads[p2]

FMU-Export in Dymola: Is it possible to make a Modelica enumeration type variable "tunable" when exported as FMU / FMI

I have implemented three similar publications in one Modelica model, using an enumeration type variable to select the publication. The goal is to switch between calculation methods (i.e. between publications) by changing the value of the enumeration type variable online.
The calculation consists of three steps, each of which has its own enumeration variable. This allows for mixed calculation methods, e.g. by setting step 1 to calculate according to publication 1 and steps 2 and 3 according to publication 2.
Each step reads something like this
model Calculation_step
type pubSelect = enumeration(
Publication_1,
Publication_2,
Publication_3);
// ####### Publication Selection #######
parameter pubSelect selection = pubSelect.Publication_2;
// ##### End Publication Selection #####
Modelica.Blocks.Interfaces.RealInput incoming;
Modelica.Blocks.Interfaces.RealOutput outgoing;
parameter Real factor = 5;
equation
if selection == pubSelect.Publication_1 then
outgoing = factor * sin(incoming);
elseif selection == pubSelect.Publication_2 then
outgoing = factor * sin(incoming)^2;
elseif selection == pubSelect.Publication_3 then
outgoing = factor * sin(incoming)^3;
else
outgoing = 99999;
end if;
annotation (uses(Publicationica(version="3.2.1"), Modelica(version="3.2.1")));
end Calculation_step;
The model will not be calculated in Dymola. Instead, a functional mock-up unit (FMU) is created using Dymola. This creates an XML file describing the model. In order to enable online changes, a variable has to have the attribute variability="tunable" set in this XML.
However, the variable selection is not tunable, as shown in the following excerpt of the XML:
-<ModelVariables>
<!-- Index for next variable = 1 -->
-<ScalarVariable name="selection" variability="constant" valueReference="100663296">
<Enumeration start="2" declaredType="Calculation_step"/>
</ScalarVariable>
Using the same code for the declaration of the variable factor yields a tunable FMU variable:
<!-- Index for next variable = 4 -->
-<ScalarVariable name="factor" variability="tunable" valueReference="16777216" causality="parameter">
<Real start="5"/>
</ScalarVariable>
tl;dr:
Is it possible to make a Modelica enumeration type variable "tunable" when exported as FMU / FMI?
Dymola Version 2015 FD01 (32-bit), 2014-11-04
I tried to add a start value to the selection parameter, and with annotation (Evaluate=false) it became tunable.
parameter pubSelect selection(start=pubSelect.Publication_2) annotation (Evaluate=false);
It will give you a warning about an unassigned parameter tho, I have not really tried if it really works(change the value at events/communication points), please let me know the result if you have a chance to give it a try. Thanks~

MATLAB/SIMULINK dynamic bus conversion with embedded Matlab function

I'm working on automated model building. In some cases I have do convert a bus into another bus (the structure is the same, but there can be variants in the names). It works for a static model where I can change the datatype of the inputs and outputs, but I didn't find any way to do this from the command line or directly in an embedded MATLAB function.
Does anybody know a way to do this?
mfb = find(sfroot, '-isa', 'Stateflow.EMChart', 'Name', 'test');
out = get(mfb, 'Outputs');
out.set('DataType', ['Bus: ' component_source.test]);