Clean MATLAB time series data - matlab

I have a Matlab time series data set, which consist of a signal that can only be 1 or 0. How can I get rid of all the values except for the changing ones?
For example:
1
1
1
0
1
0
0
0
should ideally result in
1
0
1
0
while keeping the correct time values as well of course.
Thing is, that I need to find the frequency of the signal. The time should be measured from 0->1 to the next time 0->1 occurs. The smallest time / highest frequency is what I need in the end.
Thanks!

You can use the getsamples method to get a time series which contains a subset of the original samples. Remains to identify the indices where the time series has changed, for this purpose you can use diff and logical indexing:
ts = timeseries([1 1 1 0 1 0 0 0],1:8)
ts.getsamples([true;squeeze(diff(ts.Data)) ~= 0])

A simple and clever call to to diff should be sufficient:
>> A = [1; 1; 1; 0; 1; 0; 0; 0];
>> B = A(diff([-Inf; A]) ~= 0)
B =
1
0
1
0
The code is quite simple. diff finds pairs of differences in an array. Concretely, given an array A, the output is of the following structure:
B = [A(2) - A(1), A(3) - A(2), ..., A(N) - A(N-1)];
N is the total length of the signal. This results in a N-1 length signal. As such, a trick that you can use is to append the array A with -Inf (or some high non-zero value) so that when you find the difference between the first element of this appended array and the actual first element of the true array, you will get some non-zero change. That is registered with diff([-Inf; A]). The next thing you'll want is to check is to see where the differences are non-zero. Whenever there is a non-zero difference, that is a position that you want to keep because there has been a change that occurred. This produces a logical array and so the last step is to use this to index into your array A and thus get the result.
This only extracts out the signal you need however. If you'd like to extract the time in between unique elements, supposing you had some time vector t that was as long as your signal stored in A. You would first record the logical vector in a separate variable, then index into both your time array and the signal array to extract out what you need (original idea from user dfri):
ind = diff([-Inf; A]) ~= 0;
times = t(ind);
B = A(ind);

You can make use of diff and logical to save the results as a logical array, used as a subsequent index filter in your data (say t for time and y for boolean values ))
%// example
t = 0:0.01:0.07;
y = [1,1,1,0,1,0,0,0];
%// find indices to keep
keep = [true logical(diff(y))];
%// truncated data
tTrunc = t(keep)
yTrunc = y(keep)
with the results for the example as follows
tTrunc =
0 0.0300 0.0400 0.0500
yTrunc =
1 0 1 0

Related

How to get indexes of logical matrix without using find in matlab?

Let's assume my matrix A is the output of comparison function i.e. logical matrix having values 0 and 1's only. For a small matrix of size 3*4, we might have something like:
A =
1 1 0 0
0 0 1 0
0 0 1 1
Now, I am generating another matrix B which is of the same size as A, but its rows are filled with indexes of A and any leftover values in each row are set to zero.
B =
1 2 0 0
3 0 0 0
3 4 0 0
Currently, I am using find function on each row of A to get matrix B. Complete code can be written as:
A=[1,1,0,0;0,0,1,0;0,0,1,1];
[rows,columns]=size(A);
B=zeros(rows,columns);
for i=1:rows
currRow=find(A(i,:));
B(i,1:length(currRow))=currRow;
end
For large martixes, "find" function is taking time in the calculation as per Matlab Profiler. Is there any way to generate matrix B faster?
Note:
Matrix A is having more than 1000 columns in each row but non-zero elements are never more than 50. Here, I am taking Matrix B as the same size as A but Matrix B can be of much smaller size column-wise.
I would suggest using parfor, but the overhead is too much here, and there are more issues with it, so it is not a good solution.
rows = 5e5;
cols = 1000;
A = rand(rows, cols) < 0.050;
I = uint16(1:cols);
B = zeros(size(A), 'uint16');
% [r,c] = find(A);
tic
for i=1:rows
% currRow = find(A(i,:));
currRow = I(A(i,:));
B(i,1:length(currRow)) = currRow;
end
toc
#Cris suggests replacing find with an indexing operation. It increases the performance by about 10%.
Apparently, there is not a better optimization unless B is required to be in that specific form you tell. I suggest using [r,c] = find(A); if the indexes are not required in a matrix form.

how to compare all vector indexes with a constant value and switch the value of another variable (0 1) based on that

I have a 1x24 vector (a). I should define a command in Matlab which compare all 24 values of a vector (a) with a certain value (mean (b)) and if the vector (a) item is greater than certain value (mean (b)), ''I'' sets 1 and if the vector item is less than certain value ''I'' sets 0. I wrote the below code:
for i=1:length(a)
if a(i) >= mean(b)
I = 1;
else
I = 0;
end
end
But it implements the comparison only for the last index of vector a and sets I=0. How can I fix the command that do the comparison for all indexes of vector a?
In MATLAB, you can use the following syntax to do so:
I = a >= mean(b);
If you want to use your code for doing so, you'll need to initialize I as a vector, and modify its indices as follows:
I = zeros(length(a),1)
for ii=1:length(a)
if a(ii) >= mean(b)
I(ii) = 1;
else
I(ii) = 0;
end
end
You should read about logical indexing in matlab. You don't need for loops for what you are doing. For example, if you have,
rng(5);
a = rand(1,10);
b = 0.5;
then, I = a > b; will return a logical array with zeros and ones, where one indicates the position in the array where the given condition is satisfied,
I =
0 1 0 1 0 1 1 1 0 0
Using these indices, you can modify your original array. For example, if you wish to change all values of a greater than b to be 10, you would simply do,
a(a > b) = 10;
Specifically, if you need indices where the condition is satisfied, you can use, find(a > b), which in this example will give you,
ans =
2 4 6 7 8

Assigning matrix elements to variables in a data set

Hello I'm new to Matlab.
I've written this script :
k2=2*pi();
z1 = 1;
z2 = 2;
z3 = 4;
for l = linspace(0,1,11)
A = [ -1 1 1 0 ; 1 z1/z2 -z1/z2 0 ; 0 exp(-i*k2*l) exp(i*k2*l) -1 ; 0 exp(- i*k2*l) -exp(i*k2*l) -z2/z3];
B = [ 1 ; 1 ; 0 ; 0];
D = inv(A);
C = mtimes(D,B) ;
display(C)
r = C(1,1); % this is supposed to set r = the 1,1 element in the matrix C
t = C(1,4); % see above
end
My idea for taking the values of r and t from C didnt appear to work. How can I do this properly?
Also I want to plot a graph of |r|,|t|, arg(r) and arg(t) for each value of l, my for loop overwrites the values of r and t? how can I either plot one point per loop or make r and t assign the new values so that they become lists of data.
Thanks a lot!
Matlab sets the first dimension of a matrix as row number (i.e. y position).
So you want t=C(4, 1), as you should see that the size of C is 4x1. As a note Matlab is quite good at suppressing singleton dimensions so you could do also do C(1) and C(4).
For your second point you want to set a particular element of r and t in each loop. This is the same as when you access at particular element of C when setting the values. For your case you can use the index l to determine the element. Remembering that in matlab arrays start at element 1 (not 0 as in many other languages). So you want something like r(l+1)=C(1); (or change l to start at 1).
In the more general case if you are not looping over an integer for some reason you may need to create a separate counter variable which you increase in the loop. Also it is good practice to preallocate such arrays when the size is known beforehand, often by r=zeros(11, 1) or similar (note: zeros(11) is an 11x11 matrix). This isn't significant in this case but can drastically increase execution time for large multi-dimensional arrays so is a good practice.

How to find the index of last element which is non-zero in array

I have a vector d that its size 1x1000. It stores a random values from 0 to 1. For example
d=[0.0076 0.4629 0.1554...0 0 0 0 ...0.0442 0 0 0 10^-7 10^-7 10^-7]
Now, I want to get the index of element at the last of vector (has maximize index) subject to non-zero or bigger than 10^-7). For my example, the element that has value is 0.0442 and index=?. How to implement it by MATLAB? Thank all
To find the last element that satisfies a condition, you can use the syntax find(tf, 1, 'last').
In your case, you want to find the last value that is more than a certain tolerance away from zero, i.e.
tol = 2e-7;
idx = find( abs(d)>tol, 1, 'last');
Note: I've used abs(d) so that the solution is robust to negative values in the input, and I set the tolerance to 2e-7 to increase the likelihood that the threshold is in between the most likely good values and the most likely bad values (setting it to 1e-6 may be even safer).
ind = find(d ~= 0);
ind(end) = % last nonzero index
d(ind(end)) = % last nonzero element
You can add threshold: ind = find(d > 1e-7)
If you also have negative data you may add threshold like ind = find(d > 1e-7 | d < -1e-7)
You can use a combination of max and cumsum -
tol = 1e-7; %// tolerance value
[~,index] = max(cumsum(d>tol))

How can I find the indices of the 2 smallest elements in a vector without sorting?

I'm trying to find the two smallest elements of a 1xn vector. The catch is that I can't sort it because the indices are linearly dependent upon the values (so sorting the values will screw up to original indices) AND 0 can be one of the elements. Also, elements can repeat. Here's a simplified example of my code:
a = [1,5,8,7,1];
find(a==min(a))
ans =
1 5
For a, this is the answer I was expecting.
b = [0,8,6,1,9];
find(b==min(b))
ans =
1
For b, I need it to find the 0 and the 1 so it should give me back 1 and 4 respectively for the indices. Thanks in advance!
Phil Goddard's answer is perfectly acceptable. However, you did say that you want to do this without sorting, so I'm assuming you don't want to use the sort function at all. What you can do is use min twice. Once you invoke it the first time and you find the index of the minimum element, you would set this location in your array to NaN, then run min an additional time. By setting the location to NaN, you would effectively skip the element that is equal to the smallest at that point in time. After you call min the second time, you'll get the second smallest element.
One small thing you'll need to do afterwards is to clear off the NaN you set in the array after the first min call. You do this by extracting what the minimum value was after the first call, in addition to where this minimum value was located. Once you call min a second time, you'd reset the location of where the first minimum was from NaN back to its original value.
In other words:
a = [1,5,8,7,1];
[min1,ind1] = min(a);
a(ind1) = NaN;
[~,ind2] = min(a);
a(ind1) = min1; %// Copy back to ensure we get original data back
ind1 and ind2 will contain the locations of the two smallest values in a. With your example, I get:
disp([ind1 ind2])
1 5
Similarly, for b, this is what we get with the above code:
disp([ind1 ind2])
1 4
You should use the second output from sort,
>> [~,idx] = sort(a);
>> idx(1:2)
ans =
1 5
>> [~,idx] = sort(b);
>> idx(1:2)
ans =
1 4