Often when you model systems, you want to compare different scenarios to each other. You could for example want to find out how an electrical circuit, a mechanical system, a biological network etc. behaves if you were to switch out components. (As I am writing this, I realize that switching out components in a biological network might not be as easy in the real world as in SystemModeler).
The parameters in the model can easily be changed within SystemModeler so that they correspond with the new components. However, as the number of parameters increase, this might prove tedious. One way to automate this is to follow the steps outlined in this community post.
I figured I’d share another way of doing this. With the Wolfram Language and SystemModeler, you can access data from a wide range of sources, spreadsheets, CSV, JSON, XML, HTTP, Wolfram Data Drop, databases over SQL, to name a few. If you have parameter values specified in one of these files or sources, you can easily use them directly in your simulation, making “What if” scenarios much easier to try out! Here I will focus on getting data from an excel spreadsheet, but if anyone is interested in seeing how this could be extended to databases, please let me know in a comment!
First, we need a model to simulate. I will use a very simple one, a DC-motor.
Here we have several different parameters that could correspond to different motor specifications, the resistance (R), the inductance (L) and the transformation coefficient of the EMF (EMFk) for example. We could also be interested to see how the motor behaves with different loads, changing the inertia (J).
I will create a spreadsheet that contains different motor and inertia specifications. I will also assign the different specifications some arbitrary IDs that we will use to reference them. In the real world, this could for example be article numbers.
Now we need a Wolfram Language function that can get the data out of the spreadsheet. Assuming the Specification.xlsx is located in the same directory as the notebook, the following will result in an association which can be used to query the specifications:
specs = Part[
Import[FileNameJoin[{NotebookDirectory[], "Specifications.xlsx"}]],
1];
(*Columns that contain the IDs*)
idCols = Flatten[Position[specs[[2]], "ID"]];
(*Column that contain the parameter names*)
parCols =
Append[
Table[
Range[idCols[[i]] + 1, idCols[[i + 1]] - 1],
{i, 1, Length[idCols] - 1}
],
Range[idCols[[-1]] + 1, Length[specs]]
];
(*Length of each ID column*)
idLengths = Flatten[
Map[Function[{col},
FirstPosition[specs[[3 ;; -1, col]], "", {Length[specs] - 1}] -
1], idCols]
];
(*Create an association with name, followed by ID to find parameter \
values*)
specData = Association[
Table[specs[[1, idCols[[i]]]] ->
Association[
Table[specs[[row, idCols[[i]]]] ->
Thread[
specs[[2, parCols[[i]]]] -> specs[[row, parCols[[i]]]]
],
{row, 3, idLengths[[i]] + 2}]
],
{i, Length[idCols]}
]]
<|"Motor" -> <|"A" -> {"R" -> 1000., "L" -> 0.01, "EMFk" -> 20.},
"B" -> {"R" -> 2000., "L" -> 0.02, "EMFk" -> 25.},
"C" -> {"R" -> 1000., "L" -> 0.02, "EMFk" -> 15.},
"D" -> {"R" -> 1500., "L" -> 0.01, "EMFk" -> 20.}|>,
"Inertia" -> <|"Light" -> {"J" -> 1.}, "Medium" -> {"J" -> 2.},
"Heavy" -> {"J" -> 3.}|>|>
The expression above could have been made more compact by manually specifying the column of each parameter and ID, but the above can be extended to use new components and parameters.
We can get the specifications of the motor with ID “D” with the following command:
specData["Motor", "D"]
This data can now be used when simulating SystemModeler models from the Wolfram Language. First, we will join it together with a medium inertia:
Join[specData["Motor", "D"], specData["Inertia", "Medium"]]
We can plot and simulate simultaneously:
WSMPlot[
WSMSimulate[
"MathematicaExamples.Modeling.InvertedPendulum.Components.DCMotor",
WSMParameterValues ->
Join[specData["Motor", "D"], specData["Inertia", "Medium"]],
WSMInputFunctions -> {"V" -> (12*UnitStep[# - 5] &)}],
"w"]
The DC-motor model did not have an input voltage specified, which is why it is given in the WSMSimulate command. A 12VDC unit step is used in the simulation, and it produces a plot of the angular velocity of the load:
We can also compare the performance of motor spec “A” with motor spec “B”:
WSMPlot[
Table[
WSMSimulate[
"MathematicaExamples.Modeling.InvertedPendulum.Components.DCMotor",
WSMParameterValues ->
Join[specData["Motor", motorID], specData["Inertia", "Medium"]],
WSMInputFunctions -> {"V" -> (12*
UnitStep[# - 5] &)}], {motorID, {"A", "B"}}
], "w", PlotLegends -> {"A", "B"}]
Other things that would be interesting to try out would be to instead of specifying parameter value, specifying component names and then connecting the chosen components together with WSMConnectComponents.
One could also create a dynamic interface to select between the different ID:s with the PopupMenu command, like in this community post.
Lastly, one could pull component specifications directly from the web using HTTP requests directly from the Wolfram Language.
Anyone interested in taking a stab at any of the above?
Attachments: