XOR on rising edge of two arrays
2 views (last 30 days)
Show older comments
Mohammad Zulqarnain
on 26 Dec 2020
Commented: Bruno Luong
on 27 Dec 2020
Hello,
I have two arrays containing 0's & 1's. I want to find xor of the two arrays with two additional conditions:
- The xor has to be done only in the case of rising edges.
- To distinguish which array is having rising edge first, I have assigned outputs as 3 levels i.e. 1, 0, -1
Considering an example, if 'a' and 'b' are input arrays and PWM3 is the output array;
a = [0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,0,1]
b = [0,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,1]
So, the output has be ;
PWM3 = [0,1,1,0,0,0,0,0,1,0,0,0,0,0,-1,-1,0] , so if 'a' has rising edge first output is '1', if 'b' has rising edge first output is '-1', else the output is '0'.
I am trying as given below, but I can't figure out how to take into consideration rising edges only. If someone has any idea about it, please let me know.
Thanks
for p= 1:length(a)
if(a(p)== 1 && b(p)== 0)
PWM3(p) = 1;
elseif (a(p)== 0 && b(p)== 1)
PWM3(p) = -1;
else
PWM3(p) = 0;
end
end
2 Comments
KALYAN ACHARJYA
on 27 Dec 2020
If inputs are a and b
a = [0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,0,1]
b = [0,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,1]
What would be expected output?
Accepted Answer
Bruno Luong
on 27 Dec 2020
Edited: Bruno Luong
on 27 Dec 2020
a = [0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,0,1];
b = [0,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,1];
a0 = [0; a(:)];
b0 = [0; b(:)];
i = find(diff(a0) | diff(b0));
js = find(~a0(i) & ~b0(i));
c = a(i)-b(i);
c = c(:);
i(end+1) = 0;
i = [i(js); i(js+1)];
c = [c(js); -c(js)];
k = i > 0;
PWM3 = cumsum(accumarray(i(k), c(k), [length(a),1])).'
3 Comments
Bruno Luong
on 27 Dec 2020
Jan, same old receipt after all this years. Glad you enjoy the meal as I do. Thanks.
More Answers (3)
Jan
on 27 Dec 2020
Edited: Jan
on 27 Dec 2020
a = [0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,0,1];
b = [0,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,1];
ab = a + b;
[v, n, p] = RunLength(ab == 1);
rise = strfind(ab, [0, 1]) + 1;
v((v == 1) & ~ismember(p, rise)) = 0;
PWM3 = RunLength(v, n) .* sign(a - b)
If runtime is less important or you do not have a C compiler installed, use:
% [EDITED: Function adjusted to reply row vectors]
function [out1, out2, out3] = RunLength(in1, in2)
% RUNLENGTH - RLE coding as M-function
% Author: Jan Simon, Heidelberg, (C) 2013-2020
% $License: BSD (use/copy/change/redistribute on own risk, mention the author) $
if (nargin == 1) % Encoding: [x] -> [b, n, p] --------------------
x = in1(:).';
d = [true, diff(x) ~= 0]; % TRUE if values change
b = x(d); % Elements without repetitions
k = find([d, true]); % Indices of changes
n = diff(k); % Number of repetitions
out1 = b;
out2 = n;
out3 = k(1:length(k) - 1);
else % Decoding: [b, n] -> [x] =======================
b = in1(:).'; % More convenient names for inputs
n = in2;
len = length(n); % Number of bins
d = cumsum(n); % Cummulated run lengths
index = zeros(1, d(len)); % Pre-allocate
index(d(1:len-1)+1) = 1; % Get the indices where the value changes
index(1) = 1; % First element is treated as "changed" also
index = cumsum(index); % Cummulated indices
out1 = b(index);
end
end
2 Comments
Jan
on 27 Dec 2020
A second approach:
a = [0,1,1,1,1,1,1,1,0,0,0,1,1,1,0,0,0,0,0,1];
b = [0,0,0,1,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,1];
want = [0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,-1,-1,0] % correct?
raise = strfind(or(a,b), [false, true]) + 1;
fall = strfind(xor(a,b), [true, false]) + 1;
[v, p] = sort([raise, fall]);
m = strfind(p > numel(raise), [false, true]);
q = zeros(size(a));
q(v(m)) = 1;
q(v(m + 1)) = -1;
PWM3 = cumsum(q) .* sign(a - b)
Walter Roberson
on 27 Dec 2020
if state == S_rising_A
if A(K) == 0
if B(K) == 0
state = S_zero %A was up, has fallen, B is not up, we are all 0
out(K) = 0
else
state = S_rising_B %A was up but fell, B just rose
out(K) = -1
end
elseif B(K) == 0
state = S_rising_A %A is still up, B is still down
out(K) = 1
else
state = S_clearing %A is up, B just rose, time to clear trailing edge
out(K) = 0
end
elseif state == S_rising_B
if A(K) == 0
if B(K) == 0
state = S_zero %A is not up, B was up but fell, we are all 0
out(K) = 0
else
state = S_rising_B %A is still down, B is still up
out(K) = -1
end
elseif B(K) == 0
state = S_rising_A %A just rose, B was up but just fell
out(K) = 1
else
state = S_clearing %A just rose, B is up, time to clear trailing edge
out(K) = 0
end
elseif state == S_zero
if A(K) == 0
if B(K) == 0
state = S_zero %both were down and stayed down
out(K) = 0
else
state = S_rising_B %both were down but B rose
out(K) = -1
end
elseif B(K) == 0
state = S_rising_A %both were down but A rose
out(K) = 1
else
state = S_clearing %both were down but both rose, time to clear trailing edge
out(K) = 0
end
elseif state == S_clearing
if A(I) == 0
if B(K) == 0
state = S_zero %clearing trailing edge but both were zero, stop clearing
out(K) = 0
else
state = S_clearing %clearing continuation of trailing edge
out(K) = 0
end
elseif B(K) == 0
state = S_clearing %clearing continuation of trailing edge
out(K) = 0
else
state = S_clearing %clearing continuou of trailing edge
out(K) = 0
end
end
.... Actually the above has problems.
I had to decide what to do in a case such as
1 1 1 1 0 0 0
0 0 0 0 1 1 1
which I decided should be output 1 1 1 1 -1 -1 -1 -1 -- that is, that the end of the A is considered to be "before" the beginning of the B and so the edge has ended for the first and just started for the second. So that logic is in place.
But at the same time, I had to decide what to do for
1 1 1 1 0 0 0
0 1 0 0 1 1 1
I coded the initial part as initial 1 for the A, then because both were 1 that we need to go into clearing mode, so 0 0 0 to clear the rest of the A edge. Then while we are in that clearing mode dealing with the trailing A, we ended A and started B at the same time. For consistency with the above decision that this is two distinct events with no overlap, we should stop clearing and say that we are inside a B edge, for an overall output of [1 0 0 0 -1 -1 -1] -- but the logic I implemented does not keep track of which edge(s) we are removing the trailing part of, so it just thinks "Oh, we haven't seen a clear break yet, so we must still be in clearing mode". That is arguably a bug. There should probably be an S_clearing_A state, an S_clearing_B state, and an S_clearing_both state .
.... I suspect the entire logic could be made a lot shorter by referring to the previous entries in the array. I happen to have a background in Finite State Machines, where you encode what is happening as different states without any explicit lookbacks.
... I bet it could be all coded as regular expressions...
Question for you: if the input starts with a 1, is that to be counted as a rising edge? Is there an implicit 0 before all the inputs? Or is there an implicit "we came in in the middle of something and we won't assume any rising edges until we have seen a definite absense of edges" ?
2 Comments
Walter Roberson
on 27 Dec 2020
S_* are arbitrary unique scalar values, such as categoricals or enumerations or plain 1, 2, etc. state would be initialized to S_clearing for the case where there is no implied 0.
If only one value can change at a time then the code can be simpler. I will work it out later.
See Also
Categories
Find more on Graphics Performance in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!