Convert vector to circular space with different median - matlab

I have a vector of 10 random numbers from 1 to 11 (median of the vector 1:11 is 6).
min = 1;
max = 11;
nVector = 10;
VectorRand = randi([min max],1,nVector);
I would like to convert the values in VectorRand to a circular array of 11 values, but with a different median. For example, median 2:
-5(8) -4(9) -3(10) -2(11) -1(1) 0(2) +1(3) +2(4) +3(5) +4(6) +5(7)
Result: 8 9 10 11 1 - 2 - 3 4 5 6 7
in the case of VectorRand = [1 3 8 4 6 8 5 2 6 8 10]
Result: -1 1 -5 2 4 -5 3 0 4 -5 -3
where the median (2 in this case) becomes zero and all the other values are translated in terms of distance from the median (e.g. 8=-5, 9=-4 10=-3 and so on).

The description is confusing, but here's my guess as to what you want:
>> % Set parameters
>> minVal = 1;
>> maxVal = 11;
>> newMedian = 2;
>> % Determine mapping
>> currMedian = median(minVal:maxVal);
>> map = circshift((minVal:maxVal) - currMedian, [0 newMedian - currMedian]);
This is shifting the range of values so that the median is 0 (this will eventually give you the distances from the target median), and then rotating it so the target median is at the center value of the ordering of values. Now, with the mapping built, you can map your vector to this new circulant ring:
>> VectorRand = [1 3 8 4 6 8 5 2 6 8 10];
>> Result = map(VectorRand)
Result =
-1 1 -5 2 4 -5 3 0 4 -5 -3

Related

How to insert elements in a vector at regular intervals in Matlab

I have a vector of 13 entities in Matlab.
a=[3 4 6 8 1 5 8 9 3 7 3 6 2]
I want to append values [1 2 3 4 5] at regular intervals at position 1 5 9 13 & 17.
The final value of a looks like this.
a=[1 3 4 6 2 8 1 5 3 8 9 3 4 7 3 6 5 2].
The values with italics show the appended values.
How can I do it?
Since you are looking for regular intervals, you can take advantage of the reshape and cat function:
a = [3 4 6 8 1 5 8 9 3 7 3 6 2];
v = [1 2 3 4 5];
l = [1 5 9 13 17];
interval = l(2)-l(1)-1; %computes the interval between inserts
amax = ceil(size(a,2)/interval) * interval; %calculating maximum size for zero padding
a(amax) = 0; %zero padding to allow `reshape`
b = reshape (a,[interval,size(v,2)]); %reshape into matrix
result = reshape(vertcat (v,b), [1,(size(b,1)+1)*size(b,2)]); %insert the values into the right position and convert back into vector
%remove padded zeros
final = result(result ~= 0) %remove the zero padding.
>>final =
Columns 1 through 16
1 3 4 6 2 8 1 5 3 8 9 3 4 7 3 6
Columns 17 through 18
5 2
Here's an approach using boolean-indexing -
% Inputs
a = [3 4 6 8 1 5 8 9 3 7 3 6 2]
append_vals = [1 2 3 4 5]
append_interval = 4 % Starting at 1st index
% Find out indices of regular intervals where new elements are to be inserted.
% This should create that array [1,5,9,13,17]
N_total = numel(a) + numel(append_vals)
append_idx = find(rem(0:N_total-1,append_interval)==0)
% Get boolean array with 1s at inserting indices, 0s elsewhere
append_mask = ismember(1:N_total,append_idx)
% Setup output array and insert new and old elements
out = zeros(1,N_total)
out(~append_mask) = a
out(append_mask) = append_vals
Alternatively, we can also use linear-indexing and avoid creating append_mask, like so -
% Setup output array and insert new and old elements
out = zeros(1,N_total)
out(append_idx) = append_vals
out(setdiff(1:numel(out),append_idx)) = a
a=[3 4 6 8 1 5 8 9 3 7 3 6 2]; % // Your original values
pos = [1 5 9 13 17]; % // The position of the values you want to insert
b=[1 2 3 4 5]; % // The values you want to insert
% // Pre-allocate a vector with the total size to hold the resulting values
r = zeros(size(a,2)+size(pos,2),1);
r(pos) = b % // Insert the appended values into the resulting vector first
r3 = r.' <1 % // Find the indices of the original values. These will be zero in the variable r but 1 in r3
ans =
0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1
ind= find(r3==1) % // Find the indices of the original values
ind =
2 3 4 6 7 8 10 11 12 14 15 16 18
r(ind) = a; % // Insert those into the resulting vector.
r.'
ans =
1 3 4 6 2 8 1 5 3 8 9 3 4 7 3 6 5 2
You can use this function to append a bunch of values to an existing vector, given their positions in the new vector:
function r=append_interval(a,v,p)
% a - vector with initial values
% v - vector containing values to be inserted
% p - positions for values in v
lv=numel(v); % number of elements in v vector
la=numel(a); % number of elements in a vector
column_a=iscolumn(a); % check if a is a column- or row- wise vector
tot_elements=la+lv;
% size of r is tha max between the total number of elements in the two vectors and the higher positin in vector p (in this case missing positions in a are filled with zeros)
lr=max([max(p) tot_elements]);
% initialize r as nan vector
r=zeros(column_a*(lr-1)+1,~column_a*(lr-1)+1)/0;
% set elements in p position to the corresponding values in v
r(p)=v;
% copy values in a in the remaining positions and fill with zeros missing entries (if any)
tot_missing_values=lr-tot_elements;
if(tot_missing_values)
remaining_values=cat(2-iscolumn(a),a,zeros(column_a*(tot_missing_values-1)+1,~column_a*(tot_missing_values-1)+1));
else
remaining_values=a;
end
% insert values
r(isnan(r))=remaining_values;
You can use row-wise or column-wise vectors; the orientation of r will be the same of that of a.
Input:
a =
3 4 6 8 1 5 8 9 3 7 3 6 2
v =
1 2 3 4 5
p =
1 5 9 13 17
Output:
>> append_interval(a,v,p)
ans =
1 3 4 6 2 8 1 5 3 8 9 3 4 7 3 6 5 2
Every sequence of positive positions is allowed and the function will pad for you with zeros the final vector, in case you indicate a position exceding the sum of the original vector and added items.
For example, if:
v3 =
1 2 3 4 5 6 90
p3 =
1 5 9 13 17 30 33
you get:
append_interval(a,v3,p3)
ans =
Columns 1 through 19
1 3 4 6 2 8 1 5 3 8 9 3 4 7 3 6 5 2 0
Columns 20 through 33
0 0 0 0 0 0 0 0 0 0 6 0 0 90
Hope this will help.

Matlab subscript indices error

help me please. i always get a subscript indices must either be real positive integers or logical error whenever i put 0 value on my "data" how can i get rid of it, i need to have a zero on that one. whenever there is a zero Voltage(1,0) = 1. but I can't get through.
Voltage = [0 1 1 3 4 1; 1 0 5 4 5 3; 6 4 0 4 5 7; 9 3 4 0 6 4; 7 8 5 6 0 7; 4 5 6 7 3 0];
data =[0 2 3 4; 5 6 7 8; 2 3 4 5; 4 5 6 7; 3 4 5 6; 1 3 5 7; 1 2 3 4; 3 4 5 6];
Vm = data(:,1);
Vn = data(:,2);
R = data(:,3);``
X1 = data(:,4);
sz=max(Vn)
y=1:sz
for Vm=data(:,1)
if Vm==0
Voltage(y,Vm)=1
Voltage(y,Vm)=logical(Voltage(y,Vm));
Current = Voltage(y,Vm)-Voltage(y,Vn);
else Vm >= 1
Current = Voltage(y,Vm)-Voltage(y,Vn);
end
end
You are trying to reference a value in the else statement in the Voltage matrix using y but y is not an integer it is an array (or 1d matrix). If you display y you will see that it is 1 2 3 4 5 6. There are several sections of offending code, one of which is:
else Vm >= 1
disp(y) # `y` is not an integer and therefore not a valid index.
Current = Voltage(y,Vm)-Voltage(y,Vn);
To fix it, decide if y should be static or change in the loop.
Let me know if you want a further explanation.

Find top n elements in matrix

I have a matrix which contains values and I wish to find the index of the top n minimum values.
I use the following code for finding the minimum most value:
[r,c]=find(Result==min(min(Result)));
I cant find any other questions on stack overflow which answer the question, please help
Maybe you could do something like this:
sorted = sort(Result(:));
topten = sorted(1:10);
[~,ia,~] = intersect(Result(:),topten(:)); % // Get the indices of the top ten values
[r,c]=ind2sub(size(Result),ia); % // Convert the indices to rows and columns
Or without Intersect in the other answer
[sorted,I] = sort(Result(:));
[r,c] = ind2sub(size(Result),I(1:10)); %//Change 10 to any other required value
Use prctile (Statistics Toolbox) to find the appropriate threshold, and then use indexing to select the elements above that threshold:
x = magic(4); %// example
n = 5; %// we want the top n elements
M = numel(x);
p = prctile(x(:), (M-n)/M*100);
indices = find(x>p); %// result in the form linear indices
[row, col] = find(x>p); %// result in the form of row and column indices
In this example:
>> x
x =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
>> indices.'
ans =
1 8 12 13 15
>> row.'
ans =
1 4 4 1 3
>> col.'
ans =
1 2 3 4 4
>> x(indices).'
ans =
16 14 15 13 12
Example with repeated elements:
>> x = [1 1 2 5; 3 4 3 5];
>> n = 5;
gives
>> indices.'
ans =
2 4 6 7 8
>> row.'
ans =
2 2 2 1 2
>> col.'
ans =
1 2 3 4 4
>> x(indices).'
ans =
3 4 3 5 5

Matlab: index array by Hamming Weights

a contains indices and their occurrences. Now the indexing needs to be changed with Hamming weight so that indices with equal hamming weight will be summed up. How to do the Hamming weight indexing? Any ready command for this in Matlab?
>> a=[1,2;2,3;5,2;10,1;12,2]
1 2
2 3
5 2
10 1
12 2
13 8
>> dec2bin(a(:,1))
ans =
0001
0010
0101
1010
1100
1101
Goal: index things by Hamming weight
HW Count
1 5 (=2+3)
2 5 (=2+1+2)
3 8 (=8)
You can do it as follows:
a = [1,2;2,3;5,2;10,1;12,2;13,8]
the following line needs to be added, to consider also a hammingweight of zero:
if nnz(a(:,1)) == numel(a(:,1)); a = [0,0;a]; end
% or just
a = [0,0;a]; %// wouldn't change the result
to get the indices
rowidx = sum( de2bi(a(:,1)), 2 )
to get the sums
sums = accumarray( rowidx+1, a(:,2) ) %// +1 to consider Hammingweight of zero
to get the Hammingweight vector
HW = unique(rowidx)
returns:
rowidx =
1
1
2
2
2
3
sums =
5
5
8
and all together:
result = [HW, sums]
%or
result = [unique(rowidx), accumarray(rowidx+1,a(:,2))]
result =
0 0
1 5
2 5
3 8
If you are bothered by the 0 0 line, filter it out
result(sum(result,2)>0,:)
The result for a = [0,2;2,3;5,2;10,1;12,2;13,8] would be:
result =
0 2
1 3
2 5
3 8
Try this -
a = [1 2
2 3
5 2
10 1
12 2
13 8]
HW = dec2bin(a(:,1)) - '0';
out = accumarray(sum(HW,2), a(:,2), [], #sum);%%// You don't need that "sum" option it seems, as that's the default operation with accumarray
final_out = [unique(sum(HW,2)) out]
Output -
a =
1 2
2 3
5 2
10 1
12 2
13 8
final_out =
1 5
2 5
3 8

find multiple closest values in a vector at once without "going over" (Matlab)

Let's say I have the following 2 vectors:
a = [1 3 5 7 8 9 10 15 16];
b = [2 4 14];
Is there a function I can use so that, for every element in b, I can find the index of the closest value to that element in a without "going over" the value I'm searching for? The expected output would be:
[1 2 7]
I have found previous answers that address finding the closest value, but not the closest value without exceeding the values being searched for.
Edited: now with a one-liner:
[~,index] = max(repmat(a,numel(b),1) + 0./bsxfun(#le,a,b'), [], 2)
'#% The 0./(0 or 1) creates a NaN mask where the condition
#% isn't met, leaving only the desired values in the matrix
#% max ignores NaNs, conveniently
This isn't a built-in function but it is pretty simple (link on ideone):
a = [1 3 5 7 8 9 10 15 16];
b = [2 4 14];
c = bsxfun(#minus,b',a) #%' transpose b
c(c<0)=nan; #% discard the values in a greater than b
[~,ci] = min(c,[],2) #% min ignores nan
d = a(ci) #% if you want the actual values of a
output:
c =
1 -1 -3 -5 -6 -7 -8 -13 -14
3 1 -1 -3 -4 -5 -6 -11 -12
13 11 9 7 6 5 4 -1 -2
ci =
1
2
7
d =
1 3 10