Summary
I have a working that solves my problem as described below, but would like to improve on it by eliminating the loop.
Description
I have a matrix B in Matlab of dimension (2*5)x3which is a concatenation of 2 matrices of 5 rows and where the ikth element reports an index from {1,2,3,4,5}(breaks added for clarity) . The indices can be repeated across rows. For each submatrix of dimension 5x3 of B the listed indices and the order in which they are listed coincide.
B=[0.1 0.2 |1;
0.3 0.4 |2;
0.5 0.6 |2;
0.7 0.8 |3;
0.9 1.1 |1;
---------
1.2 1.3 |1;
1.4 1.5 |2;
1.6 1.7 |2;
1.8 1.9 |3;
2.1 2.2 |1;]
Inside each submatrix of dimension 5x3 of B I would like to sum the rows with same index and get
C = [1 1.3 |1;
0.8 1 |2;
0.7 0.8 |3;
---------
3.3 3.5 |1;
3 3.2 |2;
1.8 1.9 |3;]
without looping.
What have I tried
My incomplete, but working, attempt with one loop:
D = permute(reshape(B,5,2,[]),[1 3 2]);
sum=zeros(3,2,2);
for i=1:2
E=D(:,:,i);
[b,c] = size(E);
rows = ceil(1/(c-1):1/(c-1):b);
cols = repmat(1:c-1,1,b);
sum(:,:,i) = full(sparse(E(rows,end), cols, E(:,1:end-1).'));
end
Related
I have a time vector in Matlab which does not have consistent sampling time, ex. t = [0.1 0.2 0.3 0.4 0.5 0.6 0.7 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2 2.9 3 3.1], I have another vector which is time based as a = [2 5 2 4 5 7 8 0 10 1 0 25 6 14 5 2 7 98], when I plot(t,a) there is straight line connecting the two points with larger sampling time, how can I remove these gaps where the sampling time is not consistent and it jumps to larger value? I know defining NaN between 0.7 and 1.3 and also 2 and 2.9 in t and also in a for the same interval might help, but how to distinguish if sampling time changes?
Maybe you can try the following codes, and here are two approaches that you can make it:
Approach 1: adding nan
clc;
clear;
close all;
t = [0.1 0.2 0.3 0.4 0.5 0.6 0.7 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2 2.9 3 3.1]
a = [2 5 2 4 5 7 8 0 10 1 0 25 6 14 5 2 7 98]
dt = diff(t);
idx = find(dt > mode(dt));
tC = mat2cell(t',[idx(1),diff([idx,length(t)])]);
aC = mat2cell(a',[idx(1),diff([idx,length(t)])]);
nadd = dt(idx)/mode(dt);
T = [];
A = [];
for i = 1:length(nadd)
T = [T; tC{i};ones(int32(nadd(i)),1)*nan];
A = [A; aC{i};ones(int32(nadd(i)),1)*nan];
endfor
T = [T;tC{end}];
A = [A;aC{end}];
plot(T,A)
Approach 2: dividing vector by intervals
clc;
clear;
t = [0.1 0.2 0.3 0.4 0.5 0.6 0.7 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2 2.9 3 3.1]
a = [2 5 2 4 5 7 8 0 10 1 0 25 6 14 5 2 7 98]
dt = diff(t);
idx = find(dt > mode(dt));
tC = mat2cell(t',[idx(1),diff([idx,length(t)])]);
aC = mat2cell(a',[idx(1),diff([idx,length(t)])]);
hold on;
arrayfun(#(k) plot(tC{k},aC{k}),1:(length(idx)+1));
I'm analyzing an induction motor, varying the frequency and absolute value of the stator current. Since the FEM-Tool only works with a current input, I need to vary the current over the frequency to obtain current-values of constant torque for each frequency.
To generate a mesh, I use 2 for-loops:
The outer loop sets the current.
The inner loop varies the frequency with said current, gets the machine's torque and finally, the matrices are appended adding the current stator-current, frequency and torque each in separate matrices. Plotted it looks like this:
Example of the plot using the raw data
For the plot I used smaller, more imprecise matrices and rather arbitrary values:
I_S = [ 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 ];
fre = [ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 ];
tor = [ 0 0.1 0.3 0.5 0.7 1 1.5 2 2.6 3.3 0 1.1 1.3 1.5 1.7 2 2.5 3 3.6 4.3 0 2.1 2.3 2.5 2.7 3 3.5 4 4.6 5.3 ];
While tor is shown as the colormap in the plot. Each matrix has a length of 30.
One simulation needs about 20-30 seconds. Thus, to get a precise mesh, the FEM-tool needs several hours to generate.
I would like to interpolate the spaces in between the known ones.
It seems that either the way of creating the matrices is the problem or the interp*...-functions of Octave/MATLAB simply don't work for this kind of interpolation.
Is there a way to achieve a mesh/grid-like interpolation from this type of matrices? I found many examples with x,y as variables and z as a math-function but rarely 3 linear/non-linear matrices.
Your data need to be in a meshgrid form, that is 2D:
// Known data
current = [0:2];
frequency = [0:9];
[current2D, frequency2D] = meshgrid(current,frequency);
torque2D = [ 0 0.1 0.3; 0.5 0.7 1; 1.5 2 2.6; 3.3 0 1.1; 1.3 1.5 1.7; 2 2.5 3; 3.6 4.3 0; 2.1 2.3 2.5; 2.7 3 3.5; 4 4.6 5.3 ];
// Interpolated data
currentToInterpolate = [0.5 1.5];
frequncyToInterpolate = [0.5 : 8.5];
[currentToInterpolate2D, frequencyToInterpolate2D] = meshgrid(currentToInterpolate,frequncyToInterpolate);
interpolatedTorque2D = interp2(current2D,frequency2D,torque2D,currentToInterpolate2D,frequencyToInterpolate2D);
this is my problem, for example i have an equation x + y =2, so using matlab i want to know how to determine all the possible combination of values of x and y when you add it, and will give sum of 2 (ex: x1 = 0.98, y1 =0.12; x2=0.94 y2=0.16, and etc)
i think i need to use for loop?
for x = 2-y
end
for y =2-x
end
Values of x and y
x y
0 2
0.1 1.9
0.2 1.8
0.3 1.7
0.4 1.6
0.5 1.5
0.6 1.4
0.7 1.3
0.8 1.2
0.9 1.1
1 1
so guys i need your help thanks
To get all possible combinations of x and y between 0 and 2 with a step size of 0.1 you don't even need a for loop. You can create a vector x which contains all possible x values and then calculate the corresponding y's:
x = 0:0.1:2; % Create a vector of values between 0 and 2 in steps 0f 0.1
y = 2 - x;
This will give you two (row) vectors containing all possible combinations which add up to 2.
Let's say I have a 2 by 9 matrix. I want to replace the 2 by 3 matrices inside this matrix with respect to descending sort of a(2,3), a(2,6), and a(2,9) elements. For example:
a =
0.4 0.4 0.5 0.6 0.2 0.2 0.6 0.2 0.6
0.5 0.8 0.9 0.9 0.6 0.6 0.1 0.2 0.8
[b i] = sort(a(2,3:3:end),2,'descend')
b =
0.9 0.8 0.6
i =
1 3 2
So, I want to have the following matrix:
a =
0.4 0.4 0.5 0.6 0.2 0.6 0.6 0.2 0.6
0.5 0.8 0.9 0.1 0.2 0.8 0.9 0.6 0.6
Try converting to a cell matrix first and then using your i to rearrange the cells
[b i] = sort(a(2,3:3:end),2,'descend')
A = mat2cell(a, 2, 3*ones(1,3));
cell2mat(A(i))
If for whatever reason you don't want to convert the whole of a into a cell matrix, you can do it by extending your indexing vector i to index all the columns. In your case you'd need:
I = [1,2,3,7,8,9,4,5,6]
which you could generate using a loop or else use bsxfun to get
[1 7 4
2 8 5
3 9 6]
and then "flatten" using reshape:
I = reshape(bsxfun(#plus, 3*s-2, (0:2)'), 1, [])
and then finally
a(:,I)
Typically, when a 2d matrix is separated into blocks, best practice ist to use more dimensions:
a=reshape(a,size(a,1),3,[]);
Now you can access each block via a(:,:,1)
To sort use:
[~,idx]=sort(a(2,3,:),'descend')
a=a(:,:,idx)
If you really need a 2d matrix, change back:
a=reshape(a,2,[])
sortrows-based approach:
n = 3; %// number of columns per block
m = size(a,1);
a = reshape(sortrows(reshape(a, m*n, []).', -m*n).', m, []);
This works by reshaping each block into a row, sorting rows according to last column, and reshaping back.
I've decided to get a little wild this evening and party with histogram bins to operate on some financial data I'm analyzing.
It appears the party has been pooped on, though, as the manner through which I would like to apply my 'intra-bin' operation is not readily apparent, neither through research nor playing around, and proving bothersome.
The Desire: I would like to use the 'binning' index within a column to perform some kind of row-wise 'intra-bin' operation where said operation will make a relative reference to the first element of its own bin. Please consider the following single bin example where the operation is to take a difference
A=
1 10.4
1 10.6
1 10.3
1 10.2
The relative operation will take the difference between all elements of column 2 and the 1st element of column 2 such that
bin_differencing_function(A)=
1 10.4 0.0
1 10.6 0.2
1 10.3 -0.1
1 10.2 -0.2
Now, still more convenient would be to be able to feed bin_differencing_function(A) a dual column matrix with an arbitrary number of bins such that if
A=
1 10.4
1 10.6
1 10.3
1 10.2
2 10.2
2 10.6
2 10.8
2 10.8
3 11.0
3 10.8
3 10.8
3 10.8
better_bin_differencing_function(A)=
1 10.4 0.0
1 10.6 0.2
1 10.3 -0.1
1 10.2 -0.2
2 10.2 0.0
2 10.6 0.4
2 10.8 0.6
2 10.8 0.6
3 11.0 0.0
3 10.8 -0.2
3 10.8 -0.2
3 10.8 -0.2
Most convenient would be to be able to feed better_bin_differencing_function(A) a dual column matrix with an arbitrary number of bins where the bin length may not be constant such that if
A=
1 10.4
1 10.6
1 10.3
2 10.2
2 10.6
2 10.8
2 10.8
2 10.7
3 11.0
3 10.8
best_bin_differencing_function(A)=
1 10.4 0.0
1 10.6 0.2
1 10.3 -0.1
2 10.2 0.0
2 10.6 0.4
2 10.8 0.6
2 10.8 0.6
2 10.7 0.5
3 11.0 0.0
3 10.8 -0.2
The big desire is to create a piece of code that takes advantage of vectorization (if possible) to operate on many bins who's lengths will vary between 1 and 200. I'm thinking a play on accumarray may do the trick such that
accumarray(A(:,1),A(:,2),[],#(x) fun(x))
Where fun(x) is a function with a for loop.
I'm running MATLAB 7.10.0.499 (R2010a) on Windows 7. Sorry the examples made this query so long.
Approach #1
Here's a bsxfun based approach -
%// Get the first column IDs from A and positions of the elements from
%// each ID/bin
[A_id,first_idx] = unique(A(:,1))
%// First elements from each ID/bin
first_ele = A(first_idx,2)
%// Get a 2D logical array s.t. the ones in each column represent the
%// presence of all element corresponding to each ID/bin
match_ind = bsxfun(#eq,A(:,1),A_id') %//'
%// Create the base matrix with the logical array, s.t. the ones are
%// replaced by the actual elements
base_mat = bsxfun(#times,match_ind,first_ele.') %//'
%// Final accumulate all the elements and subtract from the second column
%//of A to form the new new column for the output
out = [A A(:,2) - base_mat(match_ind)]
Approach #2
bsxfun based approach might be resource-hungry, so here's a for-loop based one that assumes sorted bins/IDs in the input data -
[A_id,first_idx] = unique(A(:,1));
[A_id,last_idx] = unique(A(:,1),'last');
out = [A A(:,2)];
for k1 = 1:numel(first_idx)
first_id = first_idx(k1);
last_id = last_idx(k1);
out(first_id:last_id,3) = out(first_id:last_id,3) - out(first_id,3);
end
Approach #3
This could be an interesting approach to test out too -
[~,first_id] = max(bsxfun(#eq,A(:,1),A(:,1)')) %//'
out = [A A(:,2) - A(first_id,2)]
Approach #4
Again, assuming sorted bins/IDs, this is a diff + cumsum based approach and appears to be the fastest given the assumptions are met -
first_match = [1; diff(A(:,1))]
first_match(first_match==1) = [1 ; diff(find(first_match))]
out = [A A(:,2) - A(cumsum(first_match),2)]
Please note that if they are not sorted, you can use sortrows as shown here -
[A,sorted_ind] = sortrows(A,1)
first_match = [1; diff(A(:,1))]
first_match(first_match==1) = [1 ; diff(find(first_match))]
out(sorted_ind,:) = [A A(:,2) - A(cumsum(first_match),2)]
You can use this technique for all other approaches that assumes sorted data to make them generalized.
Alright stackoverflow, I figured it out! Turns out I was right about using accumarray
Matrices B,C, and A are only defined within the function for validation convenience. Matrix A would be passed as follows: best_bin_differencing_function(A)
function differenced_bins=best_bin_differencing_function()
B=[1 1 1 2 2 2 2 2 3 3]';
C=[10.4 10.6 10.3 10.2 10.6 10.8 10.8 10.7 11.0 10.8]';
A=[B,C];
differenced_bins=cell2mat(accumarray(A(:,1),A(:,2),[],#(x) {fun(x)}));
end
function y=fun(var)
y=zeros(length(var),1);
for i=1:length(var)
y(i)=var(i)-var(1);
end
end
I'm going to run a stress test between this and #Divakar's response and will up-vote accordingly. Thank you all for taking a look!