Matlab: Automatically create cell array with name with meaning - matlab

I would like to name variable (type double) in the following way:
k0 = D(1,1);
k1 = D(2,2);
k2 = D(3,3);
k3 = D(4,4);
k4 = D(5,5);
k5 = D(6,6);
k6 = D(7,7);
k7 = D(8,8);
...
up to k99 automatically using for loop. So I see that I should use array or cell instead of double variable using eval as it is slow. But if I should use array or cell instead of double variable, I have to start at k{1} or k(1), which loses the meaning as I want exactly that k0 refers to D(1,1), i.e. the number in my variable is 1 less. How do I create meaningful cell name like k{0}?
Also, say I have an array A. There are also some times i need meaningful variable name, such as
c111 = A(1)*A(1)*A(1)
c222 = A(2)*A(2)*A(2)
c333 = A(3)*A(3)*A(3)
How can I create c{111} efficiently using for loop?

Use structures:
D = rand(21);
c = 1;
for k = -10:10
if k<0
s.(['k_' num2str(abs(k))]) = D(c,c);
else
s.(['k' num2str(k)]) = D(c,c);
end
c = c+1;
end
This will give you a structure like:
s =
k_10: 0.51785
k_9: 0.90121
k_8: 0.40746
k_7: 0.092989
.
.
k_1: 0.75522
k0: 0.55257
k1: 0.28708
.
.
k9: 0.94182
k10: 0.2124
and don't use eval...

Answer to 1st Question:-
D=randn(100); % A matrix of random elements of size 8x8
for m=0:99
assignin('base', ['k' num2str(m)], D(m+1,m+1))
end
Answer to 2nd Question:-
A=randn(1,3); % An array of 3 random elements
for n=1:3
assignin('base', ['c' num2str(111*n)], A(n)^3)
end
Comments:-
You've stated that you need variables like k0,k1,k2,... and c111,c222,c333 but you're asking how to create k{0}, k{1},k{2},... and c{111},c{222},c{333}. As far as your need is concerned, I have given answer to it. Regarding the latter, k{0} is never possible and c{111},c{222},c{333},... don't make good sense without using any of the first 0:100 values and then 112:221 values and so on. Although you can do it using:
A=rand(1,3); % An array of 3 random elements
c{333} = 0 ; % Pre-allocation
for p=1:3 % Since you want to use a 'for loop'
c{111*p} = A(p)^3;
end
And regarding the requirement that you made in the comment in these words "I also have some variable using negative index", you can never have variables in the negative index. If you mean you want to create variables with names like k-1, k-2,... etc, it is not possible. An alternate way is to use k_1, k_2,... etc but then as you said in the question "k0 refers to D(1,1), i.e. the number in my variable is 1 less". It means k_1 will refer to D(0,0) and so on which is again an invalid thing for MATLAB.
Recommendation:-
You really need to modify your code.

Related

Looping a Function in Matlab

total newbie here. I'm having problems looping a function that I've created. I'm having some problems copying the code over but I'll give a general idea of it:
function[X]=Test(A,B,C,D)
other parts of the code
.
.
.
X = linsolve(K,L)
end
where K,L are other matrices I derived from the 4 variables A,B,C,D
The problem is whenever I execute the function Test(1,2,3,4), I can only get one answer out. I'm trying to loop this process for one variable, keep the other 3 variables constant.
For example, I want to get answers for A = 1:10, while B = 2, C = 3, D = 4
I've tried the following method and they did not work:
Function[X] = Test(A,B,C,D)
for A = 1:10
other parts of the code...
X=linsolve(K,L)
end
Whenever I keyed in the command Test(1,2,3,4), it only gave me the output of Test(10,2,3,4)
Then I read somewhere that you have to call the function from somewhere else, so I edited the Test function to be Function[X] = Test(B,C,D) and left A out where it can be assigned in another script eg:
global A
for A = 1:10
Test(A,2,3,4)
end
But this gives an error as well, as Test function requires A to be defined. As such I'm a little lost and can't seem to find any information on how can this be done. Would appreciate all the help I can get.
Cheers guys
I think this is what you're looking for:
A=1:10; B=2; C=3; D=4;
%Do pre-allocation for X according to the dimensions of your output
for iter = 1:length(A)
X(:,:,iter)= Test(A(iter),B,C,D);
end
X
where
function [X]=Test(A,B,C,D)
%other parts of the code
X = linsolve(K,L)
end
Try this:
function X = Test(A,B,C,D)
% allocate output (it is faster than changing the size in every loop)
X = {};
% loop for each position in A
for i = 1:numel(A);
%in the other parts you have to use A(i) instead of just A
... other parts of code
%overwrite the value in X at position i
X{i} = linsolve(K,L);
end
end
and run it with Test(1:10,2,3,4)
To answer what went wrong before:
When you loop with 'for A=1:10' you overwrite the A that was passed to the function (so the function will ignore the A that you passed it) and in each loop you overwrite the X calculated in the previous loop (that is why you can only see the answer for A=10).
The second try should work if you have created a file named Test.m with the function X = (A,B,C,D) as the first code in the file. Although the global assignment is unnecessary. In fact I would strongly recommend you not to use global variables as it gets very messy very fast.

Double for loop, how to set non-continuous index?

If I want to construct a double for loop, but for index k I don't want it to be continuous index but like [1,2,4,7]. I tried to do the following, and it did not work.
for i=1:100
for k=1:2:4:7;
b(i)=i*k;
end
end
Anyone could help me deal with that?
When you want to construct an array, you don't want to necessarily use the colon (:) operator unless you want to create a range of values (like you do when you want i to be all values between 1 and 100), instead you want to use square brackets ([]) with comma separators to explicitly create an array of discrete values.
k = [1,2,4,7];
Now that you do this you can specify your loop like you had it with this small substitution for the values of k
kvalues = [1,2,4,7];
for i = 1:100
for k = 1:numel(kvalues)
b(i) = i * kvalues(k);
end
end
Notice that I have defined kvalues once outside of the loop so that it is not created every iteration through the outer loop (thanks to #dfri for pointing this oversight out)
The way that you have your loop written, you're actually over-writing the value of b(i) every time through the inner loop. I'm not sure if that's what you intended to do. If it is, then you can reduce your loop to the following:
b = k(end) * (1:100);
Otherwise, if you meant to have it be b(i,k) = i * k, you could rewrite this with bsxfun.
b = bsxfun(#mtimes, [1,2,4,7], (1:100).');
The syntax k=1:2:4:7 will not work as you intend. Usually we make use of the "two colon" syntax to describe a non-default (1) step size from the given start to end values, k = start:stepSize:end. Using an additional colon here even yields a Matlab warning ("third colon probably not intended?").
One possible workaround is to let your "non-continuous" indices reside in a vector and extract members of this vector in the inner for loop as follows
nonContIndex = [1; 2; 4; 7];
numIndices = numel(nonContIndex);
b = zeros(100,numIndices);
for i=1:100
for k=1:numIndices
b(i,k)=i*nonContIndex(k);
end
end
As noted by comments and the other answer: if b is simply a vector, your original loop will overwrite the b(i):th entry for each run of the inner loop. The above assumes that you in fact want a 2D matrix as a result.

Building a vector of multiple structure values in MATLAB

I'm trying to create a function that reads in a field of a structure to create a vector of fields. I have a structure of the form:
subject(i).stride(j).strideLength
and there are 10 subjects, about 10 strides per subject. I can create a long vector of the strideLength of all subjects, all strides with code like this:
k = 1;
for i=1:10
for j=1:size(subject(i).stride, 2)
varVector(k) = subject(i).stride(j).strideLength;
k = k + 1;
end
end
however, there are a lot of different fields I want to do this with, and I'd like to do it with a function that I can call like this:
x(1) = groupData(strideLength);
but I can't figure out the syntax to append strideLength to subject(i).stride(j). within the above loop in a function. This is what I hoped would work and didn't:
function [varVector] = groupData(var)
%groupData returns a concatenated vector of a given variable (speed, etc.)
k = 1;
for i=1:10
for j=1:size(subject(i).stride, 2)
varVector(k) = subject(i).stride(j).var;
k = k + 1;
end
end
end
Any thoughts on how to do this right? Thanks in advance!
In your groupData function, pass in the field/variable name as a string
x(1) = groupData('strideLength');
Then in the body of the code, access this field as follows
varVector(k) = subject(i).stride(j).(var);
Try the above and see what happens!

Matlab: how to implement a dynamic vector

I am refering to an example like this
I have a function to analize the elements of a vector, 'input'. If these elements have a special property I store their values in a vector, 'output'.
The problem is that at the begging I don´t know the number of elements it will need to store in 'output'so I don´t know its size.
I have a loop, inside I go around the vector, 'input' through an index. When I consider special some element of this vector capture the values of 'input' and It be stored in a vector 'ouput' through a sentence like this:
For i=1:N %Where N denotes the number of elements of 'input'
...
output(j) = input(i);
...
end
The problem is that I get an Error if I don´t previously "declare" 'output'. I don´t like to "declare" 'output' before reach the loop as output = input, because it store values from input in which I am not interested and I should think some way to remove all values I stored it that don´t are relevant to me.
Does anyone illuminate me about this issue?
Thank you.
How complicated is the logic in the for loop?
If it's simple, something like this would work:
output = input ( logic==true )
Alternatively, if the logic is complicated and you're dealing with big vectors, I would preallocate a vector that stores whether to save an element or not. Here is some example code:
N = length(input); %Where N denotes the number of elements of 'input'
saveInput = zeros(1,N); % create a vector of 0s
for i=1:N
...
if (input meets criteria)
saveInput(i) = 1;
end
end
output = input( saveInput==1 ); %only save elements worth saving
The trivial solution is:
% if input(i) meets your conditions
output = [output; input(i)]
Though I don't know if this has good performance or not
If N is not too big so that it would cause you memory problems, you can pre-assign output to a vector of the same size as input, and remove all useless elements at the end of the loop.
output = NaN(N,1);
for i=1:N
...
output(i) = input(i);
...
end
output(isnan(output)) = [];
There are two alternatives
If output would be too big if it was assigned the size of N, or if you didn't know the upper limit of the size of output, you can do the following
lengthOutput = 100;
output = NaN(lengthOutput,1);
counter = 1;
for i=1:N
...
output(counter) = input(i);
counter = counter + 1;
if counter > lengthOutput
%# append output if necessary by doubling its size
output = [output;NaN(lengthOutput,1)];
lengthOutput = length(output);
end
end
%# remove unused entries
output(counter:end) = [];
Finally, if N is small, it is perfectly fine to call
output = [];
for i=1:N
...
output = [output;input(i)];
...
end
Note that performance degrades dramatically if N becomes large (say >1000).

How can I create/process variables in a loop in MATLAB?

I need to calculate the mean, standard deviation, and other values for a number of variables and I was wondering how to use a loop to my advantage. I have 5 electrodes of data. So to calculate the mean of each I do this:
mean_ch1 = mean(ch1);
mean_ch2 = mean(ch2);
mean_ch3 = mean(ch3);
mean_ch4 = mean(ch4);
mean_ch5 = mean(ch5);
What I want is to be able to condense that code into a line or so. The code I tried does not work:
for i = 1:5
mean_ch(i) = mean(ch(i));
end
I know this code is wrong but it conveys the idea of what I'm trying to accomplish. I want to end up with 5 separate variables that are named by the loop or a cell array with all 5 variables within it allowing for easy recall. I know there must be a way to write this code I'm just not sure how to accomplish it.
You have a few options for how you can do this:
You can put all your channel data into one large matrix first, then compute the mean of the rows or columns using the function MEAN. For example, if each chX variable is an N-by-1 array, you can do the following:
chArray = [ch1 ch2 ch3 ch4 ch5]; %# Make an N-by-5 matrix
meanArray = mean(chArray); %# Take the mean of each column
You can put all your channel data into a cell array first, then compute the mean of each cell using the function CELLFUN:
meanArray = cellfun(#mean,{ch1,ch2,ch3,ch4,ch5});
This would work even if each chX array is a different length from one another.
You can use EVAL to generate the separate variables for each channel mean:
for iChannel = 1:5
varName = ['ch' int2str(iChannel)]; %# Create the name string
eval(['mean_' varName ' = mean(' varName ');']);
end
If it's always exactly 5 channels, you can do
ch = {ch1, ch2, ch3, ch4, ch5}
for j = 1:5
mean_ch(j) = mean(ch{j});
end
A more complicated way would be
for j = 1:nchannels
mean_ch(j) = eval(['mean(ch' num2str(j) ')']);
end
Apart from gnovice's answer. You could use structures and dynamic field names to accomplish your task. First I assume that your channel data variables are all in the format ch* and are the only variables in your MATLAB workspace. The you could do something like the following
%# Move the channel data into a structure with fields ch1, ch2, ....
%# This could be done by saving and reloading the workspace
save('channelData.mat','ch*');
chanData = load('channelData.mat');
%# Next you can then loop through the structure calculating the mean for each channel
flds = fieldnames(chanData); %# get the fieldnames stored in the structure
for i=1:length(flds)
mean_ch(i) = mean(chanData.(flds{i});
end