Convert vector into matrix: New row when value > X - matlab

I have a question and I can't find any solution, My problem is, that i have a vector V (m x 1). V is imported data from excel and can differ in leangth. It contains sequences of numbers >7000 and sequences of numbers < 7000. The sequences also can differ in leangth. Now I want to copy all values that are >7000 into a matrix. Everytime the value of V gets >7000 the matrix should start a new row. So that the new rows of the matrix won't differ in leangth, the shorter rows should be "filled up" with 0 until the leangth of the longest row is reached.
This is an example of how it should work.
`V [18x1]: [6000, 6500, 5000, 8000, 15000, 15500, 16000, 6000, 4000, 16500, 14000, 400, 5000, 6000, 9000, 12000, 13000, 5000]`
`Matrix [3x4]:
1.row [8000 15000 15500 16000]
2.row [16500 14000 0 0]
3.row [9000 12000 13000 0]`
I thought of first splitting the vector into several smaller vectors each time the value of V gets > 7000. And afterwards combining them to the desired matrix and delete all values < 7000. But this seems quite inconvenient to me.

A solution can be using for:
result = []; new_row = 1; col_num = 1; row_num = 0;
limit = 7000;
for idx = 1:length(V)
if(V(idx) > limit && new_row == 0) % case 1
result(row_num, col_num) = V(idx);
col_num = col_num + 1;
elseif(V(idx) > limit && new_row == 1) %case 2
row_num = row_num + 1; new_row = 0; col_num = 2;
result(row_num, 1) = V(idx);
elseif(V(idx) <= limit) %case 3
new_row = 1;
end
end
case 1 is true if before this a row is created and there is no V(j) < limit after the row creation.
case 2 is true if before this V(idx-1) < limit). and case 3 is true if V(idx) <= limit.

Related

Left and right sides have a different number of elements when trying to define conditions of a periodic signal

I'm trying to plot periodic signal that has an exponent and time conditions, but I'm getting an error in my line one_period(-5 <= t1 & t1 < 0) = exp(10*t1 - 10);.
I'm still very new to MATLAB, so I'm unsure of how to fix this error.
T = 1;
t1 = linspace(0, T, 100 + 1);
t1(end) = [];
one_period = zeros(size(t1));
one_period(-5 <= t1 & t1 < 0) = exp(10*t1 - 10);
one_period(0 <= t1 & t1 < 5) = 10;
signal = repmat(one_period, 1, 5);
signal_length = 10;
t_signal_length = linspace(0, T*signal_length, signal_length*100 + 1);
t_signal_length(end) = [];
figure;
plot (t_signal_length, signal);
You are getting an error on this line:
one_period(-5 <= t1 & t1 < 0) = exp(10*t1 - 10);
Because t1 is defined as
T = 1;
t1 = linspace(0, T, 100 + 1);
t1(end) = [];
So it is an array between 0 and 1 with 101 elements, then with the last element removed.
And the condition you've used on the erroneous line is not satisfied for any element of t1, which values are you expecting to be between -5 and 0 in an array defined as values between 0 and 1?
Therefore this -5 <= t1 & t1 < 0 is an array where every value is false, i.e you are assigning into zero indices of one_period, but you are trying to assign something (on the right of the =) which has as many values as t1. One of these does not fit into the other!
MATLAB has pretty good debugging tools, which allow you to add breakpoints, run snippets of code whilst in debug, and view variables as the code progresses. You need to have a clear idea of your expected behaviour and then run through from a breakpoint to identify which part is failing.
If you had a different condition (which actually had some true values) then maybe you just need to use this index on both sides of the assignment so that the number of values matches the number of indicies. This would look something like
bValid = 0.5 <= t1 & t1 < 0.8; % some condition for a subset within (0,1)
one_period(bValid) = exp(10*t1(bValid) - 10); % Note indexing t1(bValid) too
T = 1; %-signal period
t1 = linspace(0, T, 100 + 1); %-time series from 0 to T
t1(end) = []; %-remove last value
one_period = zeros(size(t1)); %-make function array (all zeros)
one_period(0 <= t1 & t1 < 0.5) = exp(10*t1(0 <= t1 & t1 < 0.5) - 10); %-define the signal
one_period(0.5 <= t1 & t1 < 1) = exp(10*t1(0.5 <= t1 & t1 < 1) - 10);
signal_length = 5;
signal = repmat(one_period, 1, signal_length); %-replicate the signal 5 times
t_signal_length = linspace(0, T*signal_length, signal_length*100 + 1); %-replicate the time series
t_signal_length(end) = [];
figure; %plot
plot (t_signal_length, signal);
Example plot: https://imgur.com/a/XhZnqId
As always, comments are helpful for knowing what your intentions were but here's what I think you were trying to achieve.

Referencing value of an array based on the values of another

I have an array d = [0,1000,2000]. Based on this array, I compute the value of another array, let's say J = [0,5000,8000], where J = 3*d+2000.
Now, during iteration using a for loop, if d=0, I want to extract value of J(1); if d = 1000, then I want to extract values of J(1) and J(2); if d = 2000, I want to extract values of J(1),J(2) and J(3). What would be a generic way to cross-reference values of two arrays?
Assuming your values in d are unique and the length of d and J are identical, use MATLAB's find function, especially using this version with n = 1, and direction = 'first', like so:
idx = find(d == ii, 1, 'first')
Here, ii is the desired value, e.g. 0, 1000, and so on. You'll get the index of the (first) occurrence of the desired value in d. Then, just extract all values from J from 1 to idx:
J(1:idx)
Here's a small test script:
d = [0, 1000, 2000]
J = 3 * d + 2000
% If your counter variable only contains valid values from d
for ii = d
idx = find(d == ii, 1, 'first');
printf('d = %d\n', ii);
printf('Extracted values are: ');
printf('%d ', J(1:idx));
printf('\n \n');
end
% If your counter variable may contain any value
for ii = 0:2000
idx = find(d == ii, 1, 'first');
if (~isempty(idx))
printf('d = %d\n', ii);
printf('Extracted values are: ');
printf('%d ', J(1:idx));
printf('\n \n');
end
end
And, the output looks like this:
d =
0 1000 2000
J =
2000 5000 8000
d = 0
Extracted values are: 2000
d = 1000
Extracted values are: 2000 5000
d = 2000
Extracted values are: 2000 5000 8000
d = 0
Extracted values are: 2000
d = 1000
Extracted values are: 2000 5000
d = 2000
Extracted values are: 2000 5000 8000
Hope that helps!
P.S. I haven't thought about vectorization here, since the question states, that a for loop is used in any case.

Convert vector A into matrix M at values from vector B

I have two vectors, both formatted as double.
Vector "A" is mx2. The first column contains continuous timesteps and the second column data from a measurement series.
Vector "B" is a nx2 (1<n<m) and contains several timestamps which match to some of the timesteps in vector "A".
Now I want to split vector "A" into a matrix "M".
The Matrix should start a new column, each time, the timesteps of "A" corrspond with the timestamps in the first column in vector "B" and end when they correspond with the one in the second column.
So in each row of "B", the two timestamps define a column of the matrix "M".
As the sequences between two timestamps doesn't have the same length, every row should be filled up with 0 up to a fix row. For example row 5.
The matrix should only contain the measurement data and none of the timestamps. The matrix should be formatted as double.
In an example it would look like:
vector A [18 x 2]:
1. column [11:13:30 11:13:31 11:13:32 11:13:33 11:13:34 11:13:35 11:13:36 11:13:37 11:13:38 11:13:39 11:13:40 11:13:41 11:13:42 11:13:43 11:13:44 11:13:45 11:13:46 11:13:47]
2. column [6000, 6500, 5000, 8000, 15000, 15500, 16000, 6000, 4000, 16500, 14000, 400, 5000, 6000, 9000, 12000, 13000, 5000]
vector B [3 x 2]:
1. column [11:13:33 11:13:39 11:13:44]
2. column [11:13:36 11:13:40 11:13:46]
matrix M [3 x 6]:
1. column [8000 15000 15500 16000 0]
2. column [16500 14000 0 0 0]
3. column [9000 12000 13000 0 0]
This seems like a quite complex thing to me and I hope anybody can help me with this.
The following code should do the job:
A = {
'11:13:30' 6000;
'11:13:31' 6500;
'11:13:32' 5000;
'11:13:33' 8000;
'11:13:34' 15000;
'11:13:35' 15500;
'11:13:36' 16000;
'11:13:37' 6000;
'11:13:38' 4000;
'11:13:39' 16500;
'11:13:40' 14000;
'11:13:41' 400;
'11:13:42' 5000;
'11:13:43' 6000;
'11:13:44' 9000;
'11:13:45' 12000;
'11:13:46' 13000;
'11:13:47' 5000
};
B = {
'11:13:33' '11:13:36';
'11:13:39' '11:13:40';
'11:13:44' '11:13:46';
};
fill = 5;
% Obtain the computation parameters from A...
A_len = size(A,1);
A_seq = (1:A_len).';
% Find the breakpoints of A using the values in B...
idx_beg = ismember(A(:,1),B(:,1)) .* A_seq;
idx_beg = idx_beg(idx_beg > 0);
idx_end = ismember(A(:,1),B(:,2)) .* A_seq;
idx_end = idx_end(idx_end > 0);
%Compute the maximum number of elements per row...
rows = max(idx_end - idx_beg + 1);
% Adjust the fill in order to cover enough elements...
fill = max([fill rows]);
% Create the row indexers of A based on the breakpoints...
ran = arrayfun(#(x)idx_beg(x):idx_end(x),1:numel(idx_beg),'UniformOutput',false);
% Create the final matrix with zero-padding on the right...
mat = cellfun(#(x)[[A{x,2}] zeros(1,fill-numel(x))],ran,'UniformOutput',false);
mat = cell2mat(mat(:,:).');
Final output:
mat =
8000 15000 15500 16000 0
16500 14000 0 0 0
9000 12000 13000 0 0
The code is pretty self-explanatory, but if you need clarifications feel free to ask in the comments below.
EDIT
A = [
30 6000;
31 6500;
32 5000;
33 8000;
34 15000;
35 15500;
36 16000;
37 6000;
38 4000;
39 16500;
40 14000;
41 400;
42 5000;
43 6000;
44 9000;
45 12000;
46 13000;
47 5000
];
B = [
33 36;
39 40;
44 46;
];
fill = 5;
% Obtain the computation parameters from A...
A_len = size(A,1);
A_seq = (1:A_len).';
% Find the breakpoints of A using the values in B...
idx_beg = ismember(A(:,1),B(:,1)) .* A_seq;
idx_beg = idx_beg(idx_beg > 0);
idx_end = ismember(A(:,1),B(:,2)) .* A_seq;
idx_end = idx_end(idx_end > 0);
%Compute the maximum number of elements per row...
rows = max(idx_end - idx_beg + 1);
% Adjust the fill in order to cover enough elements...
fill = max([fill rows]);
% Create the row indexers of A based on the breakpoints...
ran = arrayfun(#(x)idx_beg(x):idx_end(x),1:numel(idx_beg),'UniformOutput',false);
% Create the final matrix with zero-padding on the right...
mat = cellfun(#(x)[A(x,2).' zeros(1,fill-numel(x))],ran,'UniformOutput',false);
mat = cell2mat(mat(:,:).');
Here is the code for the question. I calculated the difference between the two timestamps of vect B. Then i checked the same timestamp in A and replaced val number of variables in M from A(2) and iterated it for all A. Adding The val variable saved from an extra nested for loop where i had to find B(i,2).
a=length(A(:,1));
b=length(B(:,1));
M= zeros(5,b);
i=1;
for j=1:a
if B{i,1} == A{j,1}
durn_vect=B{i,2}-B{i,1};
val=durn_vect(4)*600+durn_vect(5)*60+durn_vect(7)*10+durn_vect(8)+1;
for k=1:val
M(k,i)=A{j+k-1,2};
end
i=i+1;
end
if(i>3)
break
end
end

Faster way to group data in the same quartile range

Consider a column of a 10 x 10 matrix K, say K(:,1)
I would like to create a 10x4 binary matrix which tells us which quarter range the row entry belongs to. For example
ith row of binary matirx : [ 1 0 0 0 ] => K(i,1)<prctile(K(:,1),25)
My code:
%%%
K = randi(10,10);
BINMAT = zeros(size(K,1),4);
y_1 = prctile(K(:,1),25) ;
ID_1 = find(K(:,1) < y_1);
BINMAT(ID_1,1)=1;
y_2 = prctile(K(:,1),50);
ID_2 = find(( K(:,1) > y_1 & K(:,1) < y_2 ));
BINMAT(ID_2,2)=1;
y_3 = prctile(K(:,1),75);
ID_3 = find(( K(:,1) > y_2 & K(:,1) < y_3 ));
BINMAT(ID_3,3)=1;
y_4 = prctile(K(:,1),100);
ID_4 = find((K(:,1) > y_3 & K(:,1) < y_4 ));
BINMAT(ID_4,4)=1;
%%%
If I have to do this not just for one column but for a set of columns, say A = [ 1 2 5 6], and BINMAT should have 16 columns (4 for each column of K) .Is there a faster way to do this?
You can use a for loop that iterates over the desired column indexes given by A:
K = randi(10,10);
A = [1 2 5 6]; % columns in K to process
BINMAT = zeros(size(K,1), 4*length(A));
cnt = 0; % helper
for col_indx = A
y_1 = prctile(K(:,col_indx),25) ;
ID_1 = find(K(:,col_indx) < y_1);
BINMAT(ID_1, 4*cnt + 1) = 1;
y_2 = prctile(K(:,col_indx),50);
ID_2 = find(( K(:,col_indx) > y_1 & K(:,col_indx) < y_2 ));
BINMAT(ID_2, 4*cnt + 2)=1;
y_3 = prctile(K(:,col_indx),75);
ID_3 = find(( K(:,col_indx) > y_2 & K(:,col_indx) < y_3 ));
BINMAT(ID_3, 4*cnt + 3)=1;
y_4 = prctile(K(:,col_indx),100);
ID_4 = find((K(:,col_indx) > y_3 & K(:,col_indx) < y_4 ));
BINMAT(ID_4, 4*cnt + 4)=1;
cnt = cnt + 1;
end
I have noticed that many of the rows of BINMAT contain only zeros because the code you posted does not take values equal to y_1, y_2, y_3 and y_4 into account. I think you should use K(:,col_indx) >= y_1 ... and so on.
Another suggestion:
K = randi(10,10)
p = 25:25:100;
Y = prctile(K, p);
Y = [zeros(1, size(Y, 2)) ;Y];
BINMAT = zeros(size(K, 1), length(p), size(K, 2));
for j = 1:size(K, 2)
for i = 1:length(p)
BINMAT(Y(i, j) <= K(:,j) & K(:, j) <= Y(i+1, j), i, j) = 1;
end
end
Then, BINMAT(:, :, i) is the binary matrix, as you defined it, for K(:, i).
Percentile is, at its heart, the position of an element in the sorted list. So using sort directly will provide the most efficient solution, since you want multiple percentiles out of multiple columns.
First we need a way to assign fixed bins to the sorted positions. Here's the vector that I think prctile uses, but since 10 doesn't split evenly into 4 bins, it's somewhat arbitrary. (in other words, do you assign element 3 to the 0-25% bin or the 25%-50% bin)? floor(4*(0.5+(0:9).')/10)+1
Now we just need to sort each column, and assign the sort position of each original element to one of those positions. The second output of sort does most of the work:
K = randi(10,10);
A = [1 2 5 6]; % columns in K to process
BINMAT = zeros(size(K,1), 4*length(A));
bins = floor(4*(0.5+(0:9).')/10)+1;
[sortedK, idx] = sort(K(:,A));
% The k'th element of idx belongs to the c(k) bin. So now generate the output.
% We need to offset to the correct block of BINMAT for each column
offset_bins = bsxfun(#plus, bins, 4*(0:length(A)-1));
BINMAT(sub2ind(size(BINMAT), idx, offset_bins)) = 1;

Matlab: Applying threshold to one dimension in a matrix

I have a matrix M(x,y). I want to apply a threshold in all values in x, such that if x
Example:
M = 1, 2;
3, 4;
5, 6;
If t = 5 is applied on the 1st dimension, the result will be
R = 0, 2;
0, 4;
5, 6;
One way (use M(:,1) to select the first column; M(:,1)<5 returns row indices for items in the first column that are lest than 5))-
> R = M;
> R(M(:,1)<5,1) = 0
R =
0 2
0 4
5 6
Another -
R = M;
[i,j]=find(M(:,1)<5); % locate rows (i) and cols (j) where M(:,1) < 5
% so j is just going to be all 1
% and i has corresponding rows
R(i,1)=0;
To do it in a matrix of arbitrary dimensions:
thresh_min = 5;
M(M < thresh_min) = 0;
The statement M < thresh_min returns indices of M that are less than thresh_min. Then, reindexing into M with these indices, you can set all of these valuse fitting your desired criterion to 0 (or whatever else).