Simulink - Update struct parameter from initialization callback - matlab

I created a Simulink library block for a DC motor with a 'Mask' to setup the motor parameter. The mechanic part is implemented with Simscape within a subblock. The subblock also has a mask with one parameter for a structure storing the (complex) simscape configuration. This parameter is promoted to the parent mask. The Simscape configuration data struct lives in the base workspace. This approach works.
Now I tried to extend the library block for specific motor models (e.g. modelA,modelB,...). Therefore I
implemented within the 'block initialization callback' a switch/case. One case for each model. Within the case statement the specific data is load from a *.mat file and the block parameters are updated like:
cfg = load( 'modelA' );
set_param( blk, 'elec_R', num2str( cfg.elec.R ) );
set_param( blk, 'elec_L', num2str( cfg.elec.L ) );
The Simscape parameter struct is also part of the loaded config. A simple approach like:
set_param( blk, 'mech_sims', 'cfg.sims' );
fails because 'cfg' is not part of the base workspace and therefore missing during model evaluation. So my question is how can I setup my subblock with structure data which is only available within my callback function context ? Is it possible to force the evaluation from the callback function context e.g.:
Simulink.Evaluate( 'myDCMotorBlk' )

Well I found a solution. I store the simscape struct within the blocks user data:
set_param( blk, 'UserData', cfg.sims );
The mech_smi parameter is set as follows:
set_param( blk, 'mech_smi', [ 'get_param(''' blk ''',''UserData'')' ] );
Therefore during evaluation the required data is loaded from block specific user data parameter.

Related

How to update the visibility of an object based on a parameter

Connections have at least two important variables. The flow variable and not-flow variable (and then stream stuff but lets not talk about those). For clarity I will reference the Fluid connector and its variables m_flow (flow variable) and p (not flow variable).
When your building components it is important to specify if that component is setting the value for the m_flow or p. For example, you do not want to connect two pressure loss components (sets m_flow) together.
The fluid connectors in MSL are defined as port_a (design inlet) and port_b (design outlet). To specify if a port sets m_flow or not, DynamicPipe opts to use the PartialTwoPort component that has an object (black ellipse) in the icon layer that toggles its visibility based on a parameter (port_a_exposesState) which can be modified when PartialTwoPort is extended (i.e., PartialTwoPortFlow).
However, this feature does not work. The parameter will not change its display when the parameter is changed (i.e., the black ellipse on DynamicPipe never goes away).
Below is a simple example demonstrating the concept. When the model "RunMe" is simulated the parameter showBall = false because number <> 1. However, the ball is still visible.
Partial Model setting the object that should appear/disappear:
partial model ballIcon
// input Boolean showBall; // Tried this as well to no avail.
protected
parameter Boolean showBall = true;
annotation (Icon(coordinateSystem(preserveAspectRatio=false), graphics={
Ellipse(
extent={{-40,40},{40,-40}},
lineColor={0,0,0},
fillPattern=FillPattern.HorizontalCylinder,
fillColor={255,255,0},
visible=showBall)}),
Diagram(coordinateSystem(
preserveAspectRatio=false)));
end ballIcon;
Extending model:
model extendsBallIcon
extends ballIcon(showBall=(number==1));
parameter Real number = 1;
end extendsBallIcon;
Model that should show a ball that appears or disappears based on "number":
model RunMe
extendsBallIcon Ball(number=3)
annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
end RunMe;
Is there something that can be corrected to this approach so the GUI of a component when used (i.e., on the diagram layer) will work? Or do connectors GUI need to capture the flow/not-flow element that is defined by a component to assist in model usage (i.e., change port_a from description design inlet to defined flow variable).
Using Dymola 2017 (tested with the same results on Dymola 2016 as well)
Update:
Knowing the simple case works using DynamicSelect leads me to a real application. The following change appears to cause the icon to not toggle its visiblity.
In extendsBallIcon replacing:
extends ballIcon(showBall=(number==1));
parameter Real number = 1;
with
// Boolean Example
extends ballIcon(showBall=(number==true));
final parameter Boolean number = (modelStructure==Modelica.Fluid.Types.ModelStructure.av_b);
parameter Modelica.Fluid.Types.ModelStructure modelStructure = Modelica.Fluid.Types.ModelStructure.av_b;
Modelica language specification states in section 18.6.6: "Any value (coordinates, color, text, etc) in graphical annotations can be dependent on class variables using the DynamicSelect expression." That is, visible=DynamicSelect(true, showBall) in your example will display the ellipse only if showBall is true.

use argument to system object in matlab code generation

I'm tring to use system object for my generated matlab code (.mex)
here is the function.
function [ ] = filereaderTest( videofile )
fileReader = vision.VideoFileReader(videofile);
while ~isDone(fileReader)
step(fileReader);
% do something
end
release(fileReader);
end
when I try codegen filereaderTest -args videofile , error occurs.
It says "fail to compute constant value for constructor arguement #1. To generate code, all argument for System Object constructor should be constant. ..."
To use VideoFileReader, must pass file name to its constructor.
So, here is my question: there is any way to use this function to any files? for example:
filereaderTest.mex(video1);
filereaderTest.mex(video2); % video1 and video2 are different
What you are trying to do is not possible. The documentation states clearly:
Set arguments to System objectâ„¢ constructors as compile-time constants.
(1)

Load bus definitions in function's scope

How do I use Simulink.Bus.createMATLABStruct inside a function? I'm loading some bus definitions in the function's scope but createMATLABStruct doesn't see those. If I load the bus definitions in the global workspace then the function works.
Doesn't work:
function test()
load('someBuses.mat');
s = Simulink.Bus.createMATLABStruct('aBus');
end
Works:
load('someBuses.mat');
% ...
function test()
s = Simulink.Bus.createMATLABStruct('aBus');
end
Any ideas?
Simulink.Bus.createMATLABStruct accepts a 4th (undocumented) input -- open the file in the editor to see the 4th input -- which can either be 'base' (the default) or a Data Dictionary object.
The default is 'base', which is why the version you have that loads from the Base Workspace works.
Have a look at this link to find out about creating Data Dictionaries.

Specify port types in s-function blocks

I'm building my first s-function block from compiled C code. Everything is going fine, except that the s-function block demands that its interface variables are of type double, even though the underlying C interface variables are not. The block raises an error if I connect a boolean signal to the input and try to run.
I'm getting the variables in the code by calling ssGetInputPortSignal and ssGetOutputPortSignal, and casting the void pointers they return into the correct pointer types.
How do I configure the types of an s-function block's parameters in Simulink?
Take a look at ssSetInputPortDataType. Needs to be called in the S-Function mdlInitializeSizes function. In your case you'll need something like:
ssSetInputPortDataType(S, 0, SS_BOOLEAN);
Assuming the input port is the first one and you're not concerned about the return value.
The function for the outputs is ssSetOutputPortDataType, with identical use.

Changing Scope of parameter in the simbiology reaction in command line - MATLAB TOOLBOX SIMBIOLOGY

I am using Simbiology to construct a model. I am actually reading the model from an SBML file. Here is what I get after I load the model
m1
SimBiology Model - Model1
Model Components:
Compartments: 1
Events: 0
Parameters: 200
Reactions: 200
Rules: 0
Species: 100
However,
m1.Parameters gives
ans =
Empty matrix: 0-by-1
The reason I believe is because all the parameters have "Reaction" Scope. How can I make all of them "Model" Scope by command line?
Also, I was not able to access the parameter (value or scope) through Reaction Object. How do I access Parameter value and Scope (if its is scoped to Reaction)?
Any help here would be much appreciated.
Thanks!
Ayesha
P.S. - I also posted the same enquiry on the Mathworks Newsreader (user forum). Hope someone replies from there or here.
Pramod also posted an answer on the user forum, but I wanted to copy it here for completeness.
-Arthur
The following code illustrates how to change the scope of a parameter from reaction to model.
% Load lotka.
m1 = sbmlimport('lotka')
% There are no Parameters at the model level
m1.Parameters
% Copy the parameters from reactions to the model
for i = 1:numel(m1.Reactions)
p = m1.Reactions(i).KineticLaw.Parameters;
copyobj(p,m1)
delete(p)
end
m1.Parameters
Note that if there is more than one parameter with the same name there will be an error because the model requires unique names for the parameters.
As shown in the above code you can access a reaction scoped parameter by
reaction.KineticLaw.Parameters
You probably don't want to change the scope of the parameters to Model just to view them - that would change the structure of the model and potentially make it impossible to simulate.
You can view all the parameters in a model using the command
sbioselect(m1, 'Type', 'parameter')
When a parameter is scoped to a Reaction rather than the model, its parent is the Reaction's KineticLaw, rather than the Reaction itself. So if r is your reaction of interest, you can get its parameters with r.KineticLaw.Parameters.
Hope that helps!