Access/Index Array In Simulink - simulink

I have a 2D matrix/array in my model, as shown in image. I need to be able to index/access it randomly and pass it as a signal. How do I do this?
I can't use From File block, because the storage is forced to be double and too large for my embedded design.
It doesn't appear I can use From Workspace block...because this array is defined in my model as SoundArray.
This seem like it should be SO SIMPLE, but I just can’t figure it out. The only way I can think of doing it is in custom C code…which I don’t want to do.
Thanks
Array Definition and Model At Bottom

A matlab Function block (formerly EML-block) can pick up model workspace data if it is in "Parameter" scope and you define a Parameter input in the Function block. You could then use other inputs for controlling the random access, then return the desired position as a signal output from the Matlab function block.
function y = fcn(i,j,soundArray)
y = soundArray(i,j);
(Where soundArray is defined as a Parameter, and i and j are Inputs)
Edit:
Or define a Data Store Memory (add definition block). Then put a Data Store Read block for that memory which is routed to a selector block with 2 dimensions and "starting index (port)" for both those dimensions.
I believe you can use Model Workspace data to initialize the Data Store Memory, but I don't think that Model Workspace data is "live" during simulation.

Related

Simulink: Use Enumeration As Index

I feel like this is something that'd be absurdly easy in C# but is impossible in Simulink. I am trying to use an enumerated value as an array index. The trick is: I have an array that is sized for the number of elements in the enumeration, but their values are non-contiguous. So I want the defined enumeration and Simulink code to read the value at A(4). Obviously, it will instead read A(999). Any way to get the behavior I'm looking for?
classdef Example < Simulink.IntEnumType
enumeration
value1 (1)
value2 (2)
value13 (13)
value999 (999)
end
end
// Below in Simulink; reputation is not good enough to post images.
A = Data Store Memory
A.InitialValue = uint16(zeros(1, length(enumeration('Example'))))
// Do a Data Store Read with Indexing enabled; Index Option = Index vector (dialog)
A(Example.value999)
After a weekend of experimentation, I came up with a working solution: using a Simulink Function to call a MATLAB function that searches for the correct index using the "find" command. In my particular instance, I was assigning the data to Data Store Memory, so I was able to just pass the enumeration index and a new value to these blocks, but you could just as easily have a single input block that spits out the requested index. (My reputation is still too low to post pictures, so hopefully my textual descriptions will suffice.)
Data Store Memory 'A': Data type = uint16, Dimensions = length(enumeration('RegisterList'))
Simulink Function: SetValueA(ExampleEnum, NewValue)
--> MATLAB Function: SetA_Val(ExampleEnum, NewValue)
--> function SetModbusRegister(RegisterListEnum, NewValue)
global A;
if(isa(ExampleEnum, 'Example'))
A(find(enumeration('Example') == ExampleEnum, 1)) = NewValue;
end
From there, you use the Function Caller blocks in Simulink with the "Function prototype" filled in with "SetValueA(ExampleEnum,NewValue)" anywhere you wish to set this data. The logic would get more complicated if you wished to use vectors and write multiple values at once, but this is at least a starting point. It should just be a matter of modifying the Simulink and MATLAB functions to allow vector inputs and looping through those inputs in the MATLAB function.
EDIT 1
Slight update: If your MATLAB function is set up such that you cannot use variable-length vectors in it, just replace the "find" function with the "ismember" function. Using a scalar in ismember always returns a scalar, and the MATLAB compiler won't complain about it.

How can I optimize machine learning hyperparameters to be reused in multiple models?

I have a number of datasets, to each of which I want to fit a Gaussian process regression model. The default hyperparameters selected by fitrgp seem subjectively to produce less-than-ideal models. Enabling hyperparameter optimisation tends to result in a meaningful improvement but occasionally produces extreme overfitted values and is a computationally hungry process which prohibits an optimization for every model anyway.
Since fitrgp simply wraps bayesopt for its hyperparameter optimization, is it possible to call bayesopt directly to minimize some aggregate of the loss for multiple models (say, the mean) rather than the loss for one model at a time?
For example, if each dataset is contained in a cell array of tables tbls, I want to find a single value for sigma which can be imposed in calls to fitrgp for each table:
gprMdls = cellfun(#(tbl) {fitrgp(tbl,'ResponseVarName', 'Sigma',sigma)}, tbls);
Where numel(tbls) == 1 the process would be equivalent to:
gprMdl = fitrgp(tbls{1},'ResponseVarName', 'OptimizeHyperparameters','auto');
sigma = gprMdl.Sigma;
but this implementation doesn't naturally extend to a result where a single Sigma value is optimized for multiple models.
I managed this in the end by directly intervening in the built-in optimization routines.
By placing a breakpoint at the start of bayesopt (via edit bayesopt) and calling fitrgp with a single input dataset, I was able to determine from the Function Call Stack that the objective function used by bayesopt is constructed with a call to classreg.learning.paramoptim.createObjFcn. I also captured and stored the remaining input arguments to bayesopt to ensure my function call would be exactly analagous to one constructed by fitrgp.
Placing a breakpoint at the start of classreg.learning.paramoptim.createObjFcn and making a fresh call to fitrgp I was able to capture and store the input arguments to this function, so I could then create objective functions for different tables of predictors.
For my cell array of tables tbls, and all other variables kept as named in the captured createObjFcn scope:
objFcns = cell(size(tbls));
for ii = 1:numel(tbls)
objFcn{ii} = classreg.learning.paramoptim.createObjFcn( ...
BOInfo, FitFunctionArgs, tbls{ii}, Response, ...
ValidationMethod, ValidationVal, Repartition, Verbose);
end
An overall objective function can then be constructed by taking the mean of the objective functions for each dataset:
objFcn = #(varargin) mean(cellfun(#(f) f(varargin{:}),objFcns));
I was then able to call bayesopt with this objFcn along with the remaining arguments captured from the original call. This produced a set of hyperparameters as required and they seem to perform well for all datasets.

How to call simulink model(.slx) from script

I'm a super beginner in Simulink models and control systems.
I have .slx Simulink model for drone dynamics system.
It takes in two inputs (roll cmd, pitch cmd) and outputs velocity x, velocity y, position x, and position y.
From here, it seems like I can open the system by calling
open_system('myModel.slx', 'loadable');
But how do I put inputs and get output values?
Is there a way I can do this in a gui?
EDIT:
Here is the full layout of my model:
When I did
roll_CMD=10;
pitch_CMD=20;
I got a warning saying:
Input port 1 of 'SimpleDroneDynamics/...' is not connected.
How do I feed inputs using port numbers?
How do I get outputs with port numbers? I tried
[vx, vy, px, py] = sim('SimpleDroneDynamics.slx');
and got an error saying
Number of left-hand side argument doesn't match block diagram...
Is there a way to continuously feed inputs at every time step? This being controller module, I think I'm supposed to feed in different values based on output position and velocity.
EDIT2:
I'm using Matlab2017a
About the first two points of your question:
In simulink:
For the inputs you can use a constant block and when you double click the input block you can assign a value, which can be a workspace variable.
To get the outputs to your workspace you can use the simout block (make sure to put Save format to array).
Connect inputs to your simulink model
Connect outputs of your simulink model to the simout blocks.
MATLAB script
clc;
clear all;
roll = 10;
pitch = 20;
sim('/path_to_simulinkmodel.slx')
time = simout(:,1);
velocity_X = simout(:,2);
velocity_Y = simout(:,3);
position_X = simout(:,4);
position_Y = simout(:,5);
About the third point of your question
You can define the duration of your simulation in the block diagram editor. You can put a variable which is defined in the calling script. There are multiple ways of achieving time dependent input variables:
One option I personally don't recommend is using a for-loop and calling the simulink model with a different value of roll and pitch
for i = 1:numberOfTimesteps
roll = ...
...
sim('simulinkModel.slx')
end
A second and more efficient approach is changing the constant blocks to other source blocks like ramp signals or sinusoid signals
First of all Simulink model use main Matlab workspace. So you can change your variables values at command window (or just at your script) and run Simulink model.
There are several ways to initialize this constants for Simulink. One more useful way is to create script containing all your variables and load it at Simulink model starts. You can do it by adding script name in Simulink/Model Explorer/Callbacks. (There are different callbacks - on Loading, on Starting and etc.). Read more about this: here.
Now you can run your simulation using sim function:
sim('name_of_model')
name_of_model must contain path if model is not in the active MATLAB folder (active folder you can see in your matlab window just under the main menu).
There are different properties of sim function, read about them in help this can be useful for you. By the way: you can change some parameters of your model using sim. You even can find any block in your model and change it's properties. Read more about sim and about finding current blocks. Interesting that the last solution give you ability to change parameters during the simulation!
About getting output. After you run simulation you get tout variable in main workspace. It is an array of timesteps. But if you add outport block (like at my image) you also get another variable in workspace yout. yout is an Datasets. It contain all your outports values. For 2 outports for example:
yout
yout =
Simulink.SimulationData.Dataset
Package: Simulink.SimulationData
Characteristics:
Name: 'yout'
Total Elements: 2
Elements:
1 : ''
2 : ''
Get the values of any of outports:
yout.get(1).Values
it is a timeseries data type, so:
yout.get(1).Values.Time - give you times
yout.get(2).Values.Data - give you values of this outport at each time
We have one more method to take output values:
[t,x,y] = sim('model_name')
it returns double arrays. t- time array, y - matrix of all outports values (it already double and contain only values without times, but for each simulation time!)
So now you can create common Matlab GUI and work at this variables! There is no any difficulties. You can read more about GUI for Simulink here.

Setting a Simulink model Inport value from an m file

I've been doing a lot of research over the last few hours and I can't seem to figure out how to get and set a value to an Inport box. I have a simple model that has one inport and one outport and they are connected to each other. I want to set the inport value to 2 and run my simulation and see if my outport got set correctly. I read that you can't use set_param to set that value but you have to use sim(), but I'm not having any luck with that. So if anyone know how to look at the data in the inport box and/or how to set it, I'd appreciate it. Thanks!
Lucas
Ports in and out in Simulink don't work as you think. They are needed when you create subsystem - your own Simulink block, than you'll have your in and out ports.
But when you just want a make some model, and pass some data in it, and get results to Matlab, then you need To workspace and From workspace blocks. Some variable-name is assigned in their options, so you can set input data from your .m file and get results in matlab variables.
Block From workspace takes matrix variable, but if you want to pass just a number, you can use block Const and fill it value with a variable name.
Here is a screenshot, an example of in, out, to workspace and const blocks:
Here in example, I have input parameter x (block const), subsystem Gain5 and output parameter y (block To workspace). Inside the subsystem I use in and out blocks to get and return values.

Choosing MATLAB Vector element based on Simulink model argument

I'm trying to parameterize one of my Simulink models, so that I will have a gain in the model whose value is equal to an element of a MATLAB workspace vector indexed by the model parameter. That is, I want to define a model argument WheelIndex and have a gain inside the model with a value AxelLoads(WheelIndex).
When I do it exactly as I've described above, I get "vector indices must be real and positive integers" error. When I change the model argument to AxelLoad(To be used directly in the gain component) and assign its value to be AxelLoads(1)(for the first wheel) I get:
Error in 'Overview/Wheel1'. Parameter '18000.0, 15000.0, 17000.0,
21000.0' setting: "18000.0, 15000.0, 17000.0, 21000.0" cannot be evaluated.
I've also tried importing the vector as a constant block into the model, and use a selector block parameterized by the WheelIndex argument to direct the right element to a multiplication block (thereby making an ugly gain block), but then Simulink complains that I'm trying to use a model argument to define an "un-tunable value".
I just want to somehow define the parameters in the MATLAB workspace to be used in each model instance, so that I can, say, calculate the total weight by adding the loads on each wheel. Simulink seems to block all workarounds I've been trying.
Thanks
Could you use a lookup table to obtain AxelLoads vs. WheelIndex?
The easiest way is if I just came over? :P
Perhaps this explaination of tunable parameters helps a little?