Getting multiple outputs of a function in Matlab - matlab

I use a function which may return outputs more than 3 or 4 which makes it hard to assign those numbers / matrices to user defined variables one by one. Here is the example:
k = fix(log2(length(s)))
[c,l] = wavedec(s,k,'db1');
[cd1,cd2,cd3, ... , cdk] = detcoef(c,l,1:k);
k is 22 in this example. How can I get those outputs by not writing all cd's from 1 to 22?

Don't create those dynamic variables. Just use:
D = detcoef(c,l,1:k);
This will create a cell array having the same contents as of cd1, cd2, ..., cdk at its 1st, 2nd, ..., kth index respectively. Access them using D{1}, D{2},..., D{k} respectively.

Related

save columns of matrix in vector variables in Matlab

In Matlab (R2021b) I am using some given function, which reads time-dependent values of several variables and returns them in a combined matrix together with a time vector. In the data matrix each column represents one vector of time-dependent values for one variable.
[data,time] = function_reading_data_of_several_values('filename');
For readability of the following code where the variables are further processed, I would like to store these columns in separate vector variables. I am doing it like that:
MomentX = data(1,:);
MomentY = data(2,:);
MomentZ = data(3,:);
ForceX = data(4,:);
ForceY = data(5,:);
ForceZ = data(6,:);
That is working. But is there some simpler (or shorter) way of assigning the column of the matrix to individual vectors? I am asking because in real program I have more than the 6 columns as in the example. Code is getting quite long. I was thinking of something similar to the line below, but that does not work:
[MomentX,MomentY,MomentZ,ForceX,ForceY,ForceZ] = data; %does not work
Do you have any idea? Thanks for help!
Update:
Thanks to the hint here in the group to use tables, a solution could be like this:
...
[data,time] = function_reading_data_of_several_values('filename');
% data in matrix. Each column representing a stime dependent variable
varNames = {'MomentX', 'MomentX',...}; % Names of columns
T=array2table(data','VariableNames',varNames); % Transform to Table
Stress = T.MomentX/W + T.ForceY/A %accesing table columns
...
This seems to work fine and readable to me.
Solution 1: In industrial solutions like dSpace, it is very common to do it in struct arrays:
mydata.X(1).time = [0.01 0.02 0.03 0.04];
mydata.Y(1).name = 'MomentX';
mydata.Y(1).data = [1 2 3 4];
mydata.Y(2).name = 'MomentY';
mydata.Y(2).data = [2 3 4 5];
Solution 2: It is also very common to create tables
See: https://de.mathworks.com/help/matlab/ref/table.html
As already commented, it is probably better to use a table instead of separate variables may not be a good idea. But if you want to, it can be done this way:
A = magic(6): % example 6-column matrix
A_cell = num2cell(A, 1); % separate columns in cells
[MomentX, MomentY, MomentZ, ForceX, ForceY, ForceZ] = A_cell{:};
This is almost the same as your
[MomentX,MomentY,MomentZ,ForceX,ForceY,ForceZ] = data; %does not work
except that the right-hand side needs to be a comma-separated list, which in this case is obtained from a cell array.

MATLAB QUESTIONS on logical indexing and cell2struct function

First Question:
Hello there!
I am trying to assign this vector
v(mod(v,2)~=0)=0
The operations is supposed to replace odd numbers in a vector with 0. I am trying to assign this vector to result variable in a function.
something goes wrong when I try this
function
function [result1,result2] = myfunction(v)
v(mod(v,2)==0)= 0;
result1 = v;
v(mod(v,2)~=0) = 0;
result2 = v;
return
QUESTION 2:
I am trying to figure out an alternative way to express the the function cell2struct in for-loop format
for example,
if we have a cell array with 2 dimensions containing food labels. Their names, caloric count and price, each in one column. Can we write a function that's can transfer the information in cells to a struct that contain each of the fields above?
Thanks
Question #1
You are setting all even numbers to 0, but then you are using this mutated result to search for odd numbers and setting them to 0. This will probably not give you what you intended as you are using a modified copy of the original vector, so it would be prudent that you keep a copy of the vector before doing each operation.
function [result1,result2] = myfunction(v)
vcopy = v; %// Make a copy
vcopy(mod(vcopy,2)==0)= 0; %// Find even numbers and set to 0
result1 = vcopy;
vcopy = v; %// Make another copy
vcopy(mod(vcopy,2)~=0) = 0; %// Find odd numbers and set them to 0.
result2 = vcopy;
return
Question #2
Yup. If you have a list of field names stored in f and their corresponding entities for each field stored in c, simply use a loop like so:
function [s] = my_cell2struct(c, f)
for idx = 1 : numel(f)
s.(f{idx}) = c{idx};
end
The above code does no error checking, so you need to make sure that the total number of elements in c matches those of f. Also, c and f must be cell arrays. Notice that s wasn't declared at all in the function. Also, using the dot operator combined with enclosing brackets and a string that goes inside the enclosing brackets allows you to dynamically create field names on the fly. As such, for each string in f, we access the corresponding value stored in c, and we create a field name that contains this value.
Here's a reproducible example from the MathWorks documentation:
c = {'tree',37.4,'birch'};
f = {'category','height','name'};
s = cell2struct(c, f, 2)
s =
category: 'tree'
height: 37.4000
name: 'birch'
Notice that I use cell2struct here from native MATLAB to produce the above structure. Doing the above for loop which is wrapped in a function called my_cell2struct, we get:
c = {'tree',37.4,'birch'};
f = {'category','height','name'};
s = my_cell2struct(c, f)
s =
category: 'tree'
height: 37.4000
name: 'birch'

Storing each iteration of a loop in Matlab

I have a 2d matrix (A=80,42), I am trying to split it into (80,1) 42 times and save it with a different name. i.e.
M_n1, M_n2, M_n3, … etc (representing the number of column)
I tried
for i= 1:42
M_n(i)=A(:,i)
end
it didn't work
How can I do that without overwrite the result and save each iteration in a file (.txt) ?
You can use eval
for ii = 1:size(A,2)
eval( sprintf( 'M_n%d = A(:,%d);', ii, ii ) );
% now you have M_n? var for you to process
end
However, the use of eval is not recommanded, you might be better off using cell array
M_n = mat2cell( A, [size(A,1)], ones( 1, size(A,2) ) );
Now you have M_n a cell array with 42 cells one for each column of A.
You can access the ii-th column by M_n{ii}
Generally, doing if you consider doing this kind of things: don't.
It does not scale up well, and having them in one array is usually far more convenient.
As long as the results have the same shape, you can use a standard array, if not you can put each result in a cell array eg. :
results = cell(nTests,1)
result{1} = runTest(inputs{1})
or even
results = cellfun(#runTest,inputs,'UniformOutput',false); % where inputs is a cell array
And so on.
If you do want to write the numbers to a file at each iteration, you could do it without the names with csvwrite or the like (since you're only talking about 80 numbers a time).
Another option is using matfile, which lets you write directly to a variable in a .mat file. Consult help matfile for the specifics.

Keeping Some MATLAB Function Input Arguments Inactive

I have a function which takes 11 pairs of input arguments (each pair representing a type of process and an input commodity) and calculates a result based on all of those 22 values. However, I would like to make the function flexible such that if I wanted to use, for example, 3 pairs of input arguments rather than 11, it would still come up with a result and meanwhile ignore the other 8 pairs of unused arguments. Can you please tell me the simplest way to do that?
I've tried using varargin but when I pass fewer than 22 values as the input arguments, MATLAB tells me that the 'the (varargin) index (in the function file) exceeds the marix dimensions.'
Is there any way to pass 'inactive' input arguments so that MATLAB simply doesn't perform any operation on them?
Thanks.
Here's a sample of my code in the function file:
function [ Eprout,AnnEprout,Demand,AnnDemand,Status,AnnStatus ] = supdem(time, country, weights,supdataset,output, demdataset,... process1,process2,process3,process4,process5,process6,process7,process8,process9,process10,process11,... ipcom1,ipcom2,ipcom3,ipcom4,ipcom5,ipcom6,ipcom7,ipcom8,ipcom9,ipcom10,ipcom11)
Eprout = (sum(sum(supdataset(time,country,process1,ipcom1,output)))+sum(sum(supdataset(time,country, process2,ipcom2,output)))+ ... sum(sum(supdataset(time,country,process3,ipcom3,output)))+sum(sum(supdataset(time,country, process4,ipcom4,output)))+ ... sum(sum(supdataset(time,country,process5,ipcom5,output)))+sum(sum(supdataset(time,country, process6,ipcom6,output)))+... sum(sum(supdataset(time,country,process7,ipcom7,output)))+sum(sum(supdataset(time,country, process8,ipcom8,output)))+ ... sum(sum(supdataset(time,country,process9,ipcom9,output)))+sum(sum(supdataset(time,country, process10,ipcom10,output)))+... sum(sum(supdataset(time,country,process11,ipcom11,output))))/1000;
There are a number of ways of doing this. A simple alternative to varargin is to pass a logical vector with 0/1 values. In your case, the vector would contain 11 entries. The value of each entry would signal to the function whether to expect that variable pair in a separate array. Within the function you could have a series of if statements to check whether an entry in v is 1 or 0, for instance:
function [myoutputs] = myfunction(array_1,array_2,...., v);
default_1 = some_values1; % change some_values1 to whatever should be defaults for variable 2
default_2 = some_values2; % change some_values2 to whatever should be defaults for variable 2
% ... additional default initializations
if v(1)
pair_1 = array_1;
else
pair_1 = default_1;
end
% ... if statements for remaining pairs...
% ... use pair_1 pair_2 ...
For instance, passing the vector
v = [1 zeros(1,9) 1];
would indicate to the function that only the first and last parameter pairs are to be used.
You should still pass 11 pairs, but the content of the pairs you do not want to use can be empty or some other value.

MATLAB: Using second output of a function in a inline function [duplicate]

Say I want to create an anonymous function from a m-file-function that returns two outputs. Is it possible to set up the anonymous function such that it only returns the second output from the m-file-function?
Example: ttest2 returns two outputs, t/f and a probability. If I want to use the t-test with cellfun, I might only be interested in collecting the probabilities, i.e. I'd like to write something like this
probabilities = cellfun(#(u,v)ttest2(u,v)%take only second output%,cellArray1,cellArray2)
There's no way I know of within the expression of the anonymous function to have it select which output to return from a function with multiple possible output arguments. However, you can return multiple outputs when you evaluate the anonymous function. Here's an example using the function MAX:
>> data = [1 3 2 5 4]; %# Sample data
>> fcn = #(x) max(x); %# An anonymous function with multiple possible outputs
>> [maxValue,maxIndex] = fcn(data) %# Get two outputs when evaluating fcn
maxValue =
5 %# The maximum value (output 1 from max)
maxIndex =
4 %# The index of the maximum value (output 2 from max)
Also, the best way to handle the specific example you give above is to actually just use the function handle #ttest2 as the input to CELLFUN, then get the multiple outputs from CELLFUN itself:
[junk,probabilities] = cellfun(#ttest2,cellArray1,cellArray2);
On newer versions of MATLAB, you can replace the variable junk with ~ to ignore the first output argument.
One way to do this is to define the function:
function varargout = getOutput(func,outputNo,varargin)
varargout = cell(max(outputNo),1);
[varargout{:}] = func(varargin{:});
varargout = varargout(outputNo);
end
and then getOutput(#ttest2,2,u,v) gives only the p-value.
To use it in a cellfun you would need to run:
probabilities = cellfun(#(u,v)getOutput(#ttest2,2,u,v)...
This eliminates the need to write a wrapper every time, but then you have to make sure this function is always in the path.