Splitting non-continuous sized matrix in vectors - matlab

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.

Related

Reading multiple numbered data variables from the workspace

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')

Performing operations on a variable number of workspace elements in MATLAB

new MATLAB user here so apologies if this seems like a silly question. I have the following list of variables (doubles) in my workspace:
E1_01Strain E1_06Strain E1_07Strain E1_08Strain E1_09Strain E1_10Strain
E1_01Stress E1_06Stress E1_07Stress E1_08Stress E1_09Stress E1_10Stress
These are lists of numbers. I would like to remove the last n elements from each variable. I can do it with the command
E1_01Strain = E1_01Strain(1:end-100)
but it's impractical because later I'm going to have to do it on many, many more similar variables. Therefore I wanted to write a function that accepts as inputs a list of the workspace variables (as in, I highlight the variables I want and drag and drop into the function input) and removes from each one n elements.
I understand that I can write a function like this:
function [X1, X2, X3, X4] = Remove_n_elements[n, X1, X2, X3, X4]
X1 = X1(1:end-100);
X2 = X2(1:end-100);
X3 = X3(1:end-100);
X4= X4(1:end-100);
end
but that would mean that I would have to change the number of inputs, outputs, and the lines of code in the function every time. I'm sure there's a better way to do it but I can't figure it out.
I keep thinking that there might be a way to do it by looping over all the inputs but I can't get it to work since (as far as I know) I need to create a list of the inputs and then the operation is performed only on the elements of that list, not the inputs themselves.
I was looking at Passing A Variable Number of Arguments into a Function and from that using inputParser from https://www.mathworks.com/help/matlab/matlab_prog/parse-function-inputs.html but since I'm new to MATLAB I'm not sure how to use it for my case.
I used the code provided by il_raffa for a bit but followed his advice and went back and reconsidered how the script functions. After some more digging I wrote the following script that does exactly what I need. This script extracts the columns des_cols from all .csv files in a folder and plots them together. It then makes another plot of the averages.
files = dir('*.csv'); % navigate to the folder that you want to run the script on in MATLAB
avgStress = [];
avgStrain = [];
set(groot, 'DefaultLegendInterpreter', 'none') % the names of my .csv files have underscores that I want to see in the legend, if you don't want this then comment this line
hold on; %comment this and hold off further down if you want separate plots for every .csv
for file = files'
csv = xlsread(file.name);
[n,s,r] = xlsread(file.name);
des_cols = {'Stress','Ext.1(Strain)'}; % type here the names of the columns you want to extract
colhdrs = s(2,:);
[~,ia] = intersect(colhdrs, des_cols);
colnrs = flipud(ia);
file.name = n(:, colnrs);
file.name = file.name(1:end-600,:); % I wanted to remove the last 600 rows but if you want them all, remove the -600
plot(file.name(:,2),file.name(:,1),'DisplayName',s{1,1});
avgStress = [avgStress file.name(1:1500,1)]; % calculates the average stress for the first 1500 points, you can change it to whatever you want
avgStrain = [avgStrain file.name(1:1500,2)];
end
ylabel({'Stress (MPa)'}); % y-axis label
xlabel({'Strain (%)'}); %x-axis label
title({'E_2'}); % title of the plot
legend('show');
hold off; % commment this if you want different plots for all .csv files
avgStress = mean(avgStress,2);
avgStrain = mean(avgStrain,2);
plot(avgStrain,avgStress);
This creates two plots, one with all the raw data and another with just the averages. I hope this helps anyone that might have a similar issue.
The best thing you can do is to review the architecture of your SW in order to avoid the needs to perform such operations on the Workspace variables.
That is: how those variables are created? Are these variables loaded from a ".mat" file? etc.
Anyway, in order to avoid using the eval function and given your situation, a possible approach could be:
identify the names of the varailbes by using the function who. You can specify in the call to who the root name of the varaibles and use the * as, for example, who('E1*'). Make sure it fit wiht the desired variables. You can also use regexp to better refine the selection of the variables
save these varaibles in a temporary .mat file: the name (including the path of the temporary file can be created with the function tempname
load the temporary .mat file: this will create a struct in the Workspace whose fields are the variables you want to midify
call the function to remove the undesired elements form the fields of the struct. The function have to return the updated struct
save the updated struct in the temporary file
load again the temporary file by specifying the option -struct which allows loading the content of the file as single varaibles
The function to remove the undesired elements can be made as follows:
get the nams of the struct's fields by using the function fieldnames
loop over the filed of the struct by using the dynamic field names property
remove the undesired elements form the fields
return the updated struct
A possible implementatin could be:
Code "before" the call to the function
% Get the names of the variables
list_var=who('E1*')
% Define the name of a temporary ".mat" file
tmp_file=tempname
% Save the variables in the temporary ".mat" file
save(tmp_file,list_var{:});
% Load the variables in a struct
sel_vars=load(tmp_file);
% Call the function to remove the elements
out_str=Remove_n_elements(8,sel_vars)
Function to remove the undesired elements
function sel_vars=Remove_n_elements(n,sel_vars)
% Get the names of the fields of the struct
var_names=fieldnames(sel_vars)
% Loop over the fields and remove the undesired elements
for i=1:length(var_names)
sel_vars.(var_names{i})=sel_vars.(var_names{i})(1:end-n)
end
Code "after" the call to the function
% Save the updated struct in the temporary ".mat" file
save(tmp_file,'-struct','out_str')
% Load the updated struct as separate variables
load(tmp_file)

Looping over list of variables in matlab

I have a list of variables (different sized numeric matrices) named Reach1 to Reach7
I want to plot them all as subplots in one figure.
Need a way to loop over each variable as below:
names = {'Reach1' 'Reach2' 'Reach3' 'Reach4' 'Reach5' 'Reach6' 'Reach7'};
for index = 1:7
subplot(3,3,index)
plot(names(index)(:,1),names(index)(:,2));hold on;
plot(names(index)(:,5),names(index)(:,6));
plot(names(index)(:,9),names(index)(:,10));hold off;
end
Is there a better way to do this in matlab?
You cannot access names(index) because it is cell array and those are accessed by names{index}.
If you want to access variable Reach1(1,3) by calling names{1}(1,3), you will fail because Matlab will (try to) return a as an element of char array. This approach can be achieved by eval but do NOT do that! It has many drawbacks and no benefit.
You can simplify your code using Matlabs features, that are not obvious but bloody useful.
Suppose we have all matrices in one cell array Reaches={<Reach1>;<Reach2>;...}:
Reaches={rand(4,12);rand(6,12);rand(8,12);rand(2,12);rand(9,12)}; %declare dummy variables
counter=0;
for Reach=Reaches
counter=counter+1;
subplot(3,3,counter);
plot(Reach(:,[1,5,9]),Reach(:,2,6,10));
end
This code benefits from:
for is able to loop over array elements.
plot is able to process arrays.
(Advanced) Array indexing.
In this example appropriate element names{ii} is passed to Reach variable, counter counter is advanced and plot is supported by matrices containig columns 1, 5 and 9 and 2, 6 and 10 as x and y values, respectively.

Input Parameters of a 'From Workspace' Block in Simulink

I have a .mat file which has a structure loaded into the Workspace. I have created a simulink model and want to Import the signals from the Workspace. What should be the Input value for the Data Parameter of the 'From Workspace' block. The Name of the structure is Measurements, the Signal Name is B_cal and it has further elements as time,name, Units and value. I know that the structures can be accessed by somewhat like this command :
Measurements.B_cal.value
But i am unable to set the Input Parameters. Could anyone help me with this ?
There are some limitation to use structures through the FromWorkspace block:
A MATLAB expression that evaluates to one of the following:
A MATLAB timeseries object
A structure of MATLAB timeseries objects
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.
A structure, with or without time, which contains:
1) A signals.values field, which contains a vector of signal values
2) An optional signals.dimensions array, which contains the dimensions of the signal
3) An optional time vector, which contains time stamps
More useful information you can find in help.
So in your case you can use different methods. I'll give some examples:
1) define your struct in necessary format:
t = (1:10)'; %'
v = [6 9 3 1 7 0 7 3 8 1]'; %'
measure.time = t;
measure.signals.values = v;
Important moment here: t andv must be a columns! rows will not work!
If you need to use several rows of data use multidimensional v and add
measure.signals.dimentions = size(v,2);
2) You can see ths time field is an optional. If you do not have it you need to set Sample time in block other than 0 and, clear Interpolate Data, Set Form output after final data value by to a value other than Extrapolation. Furthermore, you need to define time field:
mystruct.time = [];
3) If you don't want to change your structure, you can use next:
t = (1:10)'; %'
and set this in Data of FromWorkspace block: [t, Measurements.B_cal.value].
4) There are some useful methods: use timeseries or just matrix. But it's not really your case if you need to use your structure.

add outputs to anonymous function in loop

I have a system of equations contained in an anonymous equation. Instead of defining all of the equations when i create the function, I would like to add one in each step of a for loop. Is this possible?
I suppose if you have a linear set of equations, you can construct it using a matrix, then you're free to include new operations by adding rows and columns to the matrix and/or its accompanying right hand side vector.
If you're really trying to use anonymous functions, say if your functions are non-linear, then I would suggest you to look into arrays of anonymous functions. For example,
A = cell(3,1); % Preallocate a 3 by 1 cell array
for ii = 1:3
A{ii} = #(x) x^2+ii; % Fill up the array with anonymous functions
end
Now if you check what's contained in cell array 'A',
A = #(x)x^2+ii
#(x)x^2+ii
#(x)x^2+ii
Don't worry about the display of 'ii' instead of the actual number of the loop variable as we gave it earlier, MATLAB has internally replaced them with those values. Changing 'ii' in the current function scope will also not affect their values in 'A' either. Thus,
A{1}(2) = 5, A{2}(2) = 6 and A{3}(2) = 7
If you're not familiar with cell arrays, you can read up on its usage here.
Again, what you're trying to achieve might be different. I hope this works for you.