I want to import several arrays of data into Simulink so that I can cycle through each of those arrays, operating on one column at a time, and choosing a different array at random intervals. (So let's say I start cycling through the columns of array 1 for 1 second, then I'll move over to array 2, then array 3 and back to array 1).
I can't use From File blocks because each column then has a specific timestamp associated to it, so I can neither cycle, nor start the simulation selecting a different array each time.
Is there a solution to this problem in Simulink?
Use a MATLAB Function Block. Have your array input to it as a Parameter, which means it'll pick the whole array up from the MATLAB Workspace during model initialization.
Depending on how you want to index into the matrix -- you haven't given enough information to determine this -- you could either,
have 2 signals input to the MATLAB Function block that represent a row index and column index. You'd then have logic in the model that specifies these signal/index values.
have 2 persistent variables within the MATLAB Function block that define the row and column indices. Have logic in the block that specify how these variables change each time step.
Related
For reading time-based data of variables from the Matlab workspace in Simulink (for time-based inter- and extrapolation), a typical solution is the use of the From Workspace block, by e.g. providing variable input data var in the following structure format:
var.time=[nx1]
var.signals.dimensions=m
var.signals.values=[nxm]
for providing the data of m variables with n time-based samples. Since variables' data is stored in a single matrix, it is implied that all variables are required to have the same (number of) time stamps.
If this is not the case, a solution could be the use of multiple From Workspace blocks, and corresponding variable input data structs (e.g. varA, varB, varC, etc.), like so:
However, this solution requires the number of variables to be fixed for all simulations. In my case, variables are numbered (rather than named) and the number of variables might not be the same from one simulation to the next. As such, for generalization purposes, I would like to find a solution without having to change the simulation file. A first step in this direction is the use of a struct array (i.e. var(1), var(2), var(3), etc.), which works:
A candidate next step is then to use a For Iterator to loop over N variables (and then to assign and concatenate the output in some output array, which I know can be done and is not the focus here):
The problem here is that the index id can't be fed to the From Workspace block! I ran into an identical issue when trying to solve the problem with a lookup table block. How to solve this problem of reading multiple but varying number of data variables from the workspace with different (number of) time stamps? Solutions that don't use a From Workspace or lookup table block are welcome too.
Here is equivalent code for running the whole thing in Matlab instead of Simulink:
% DEFINED IN MATLAB:
% Examplary input of variable data with different time stamps, according to
% Simulink structure conventions (.time, .signals etc)
N=3; % number of variables
for id=N:-1:1
var(id).time = linspace(0,2,id*2+2)';
var(id).signals.dimensions = 1;
var(id).signals.values = sin((var(id).time-id)*pi/2)';
end
% TO BE EXECUTED IN SIMULINK:
% the simulink clock time:
t = 1.234; % random time
for id=N:-1:1
var_t(id) = interp1(var(id).time,var(id).signals.values,t);
end
And here a figure to illustrate the results:
% Figure code:
figure(1),clf
colors=lines(N);
for id=1:N
plot(var(id).time,var(id).signals.values,'*-','color',colors(id,:)),hold on
plot(t,var_t(id),'o','color',colors(id,:))
end
xlabel('time'),ylabel('variable data')
I'm writing an piece of software within Matlab. Here, the user can define a dimension say 3.
This dimension is subsequently the number of iterations of a for loop. Within this loop, I construct a matrix to store the results which are generated during every iteration. So, the data of every iteration is stored in a row of a matrix.
Therefore, the size of the matrix depends on the size of the loop and thus the user input.
Now, I want to separate each row of this matrix (cl_matrix) and create separate vectors for every row automatically. How would one go on about? I am stuck here...
So far I have:
Angle = [1 7 15];
for i = 1:length(Angle)
%% do some calculations here %%
cl_matrix(i,:) = A.data(:,7);
end
I want to automate this based on the length of Angle:
length(Angle)
cl_1 = cl_matrix(1,:);
cl_7 = cl_matrix(2,:);
cl_15= cl_matrix(3,:);
Thanks!
The only way to dynamically generate in the workspace variables variables whos name is built by aggregating string and numeric values (as in your question) is to use the eval function.
Nevertheless, eval is only one character far from "evil", seductive as it is and dangerous as it is as well.
A possible compromise between directly working with the cl_matrix and generating the set of array cl_1, cl_7 and cl_15 could be creating a structure whos fields are dynamically generated.
You can actually generate a struct whos field are cl_1, cl_7 and cl_15 this way:
cl_struct.(['cl_' num2str(Angle(i))])=cl_matrix(i,:)
(you might notice the field name, e. g. cl_1, is generated in the same way you could generate it by using eval).
Using this approach offers a remarkable advantage with respect to the generation of the arrays by using eval: you can access to the field od the struct (that is to their content) even not knowing their names.
In the following you can find a modified version of your script in which this approach has been implemented.
The script generate two structs:
the first one, cl_struct_same_length is used to store the rows of the cl_matrix
thesecond one, cl_struct_different_length is used to store arrays of different length
In the script there are examples on how to access to the fileds (that is the arrays) to perform some calculations (in the example, to evaluate the mean of each of then).
You can access to the struct fields by using the functions:
getfield to get the values stored in it
fieldnames to get the names (dynamically generated) of the field
Updated script
Angle = [1 7 15];
for i = 1:length(Angle)
% do some calculations here %%
% % % cl_matrix(i,:) = A.data(:,7);
% Populate cl_matrix
cl_matrix(i,:) = randi(10,1,10)*Angle(i);
% Create a struct with dinamic filed names
cl_struct_same_length.(['cl_' num2str(Angle(i))])=cl_matrix(i,:)
cl_struct_different_length.(['cl_' num2str(Angle(i))])=randi(10,1,Angle(i))
end
% Use "fieldnames" to get the names of the dinamically generated struct's field
cl_fields=fieldnames(cl_struct_same_length)
% Loop through the struct's fileds to perform some calculation on the
% stored values
for i=1:length(cl_fields)
cl_means(i)=mean(cl_struct_same_length.(cl_fields{i}))
end
% Assign the value stored in a struct's field to a variable
row_2_of_cl_matrix=getfield(cl_struct_different_length,(['cl_' num2str(Angle(2))]))
Hope this helps.
When I'm trying load data, from Matlab to Simulink, I get this error:
Error using TSFPnew (line 191)
Invalid matrix-format variable specified as workspace input in 'modelTSFP/From Workspace5'. The matrix
must have two dimensions and at least two columns. Complex signals of any data type and non-double
real signals must be in structure format. The first column must contain time values and the remaining
columns the data values. Matrix values cannot be Inf or NaN.
I have very simple model (I know, it be easier to do this computation on Matlab, but this is only fragment of my model):
All data have these same dimension 1x144:
Why I can't just load it to the Simulink space?
The error message is pretty self-explanatory: the data in the From Workspace block represents a time dependent variable so if you are using an array, the first column of the array must be the time values and the second (or more) columns the corresponding data points. Check the documentation for more details. Your data appears to be only vectors, where is the corresponding time data for your values?
If you want a parameter (that doesn't vary with time), then don't use a From Workspace block, use a Constant block instead.
how to use the "from workspace block in simulink" ?
I have tried using the from workspace block by given 10*2 matrix as input. it is appending some extra data along the data I have given .
and I have such 3 such blocks and want to know how I merge them.
Read the documentation. Simulink is time-based so the data in your From Workspace block must be as a function of time. Does your 10 x 2 matrix represent a signal as a function of time? If so, it needs to be as follows:
A two-dimensional matrix:
The first element of each matrix row is a
time stamp.
The rest of each row is a scalar or vector of signal
values.
The leftmost element of each row is the time stamp of the
value(s) in the rest of the row.
10 values isn't very much, it's likely that Simulink will need additional data points at intermediate times, if you have the Interpolate Data check box ticked. If not, "the current output equals the output at the most recent time for which data exists".
I think you may have a misunderstanding of the variables intended to be read by the FromWorkspace block.
The block expects a time series defining the value at various points in the simulation.
The From Workspace block help should point you in the right direction on this. Mathworks Help Documentation
I believe that something like the following would work for you:
>> WorkspaceVar.time=0;
>> WorkspaceVar.signals.values=zeros(10,2)
>> WorkspaceVar.signals.dimensions = [10,2]
I have a .mat file with a 1x200 structure (corresponding to 200 experimental sessions). In each of these cells there is a matrix of different lengths (made up of 600-800 1x1 structures, corresponding to the number of trials in each session). Within each of these structures (trials) there are single values which I wish to store separately. How should I go about this?
allData <1x200 struct> (All sessions)
allData(1,1) <1x1 struct> (1 session)
allData(1,1).trial <600-800x1 struct> (All trials in 1 session, # of trials is variable)
allData(1,1).trial(1,1).value (What I want to store)
Thanks a lot!
I think you are looking for a nested loop:
OUTPUT = [];
for I=1:size(allData,2)
for J=1:size(allData(1,I).trial,1)
OUTPUT(end+1) = allData(1,I).trial(J,1).value;
end
end
Additional explanations:
When using the size function in Matlab for-loop statements, it is important to check (if necessary in the debug mode) that the correct dimension is selected. That is why, based on the data format in question here, it says size(X,2) first, because it is a 1x200 structure, so we are interested in the 2nd dimension; and size(Y,1) second, because it is a 600x1 structure.
As the overall dimension of OUTPUT may be difficult to determine a priori, it is initialized as empty vector. This is important for the (end+1) 'counter' to work, which will fail, if the variable isn't know when the command is called first. Thereafter, it will simply append the value to OUTPUT.