MATLAB: Subsetting one array by values of a second - matlab

I basically have two columns (arrays): column A represents a continuous stream of data across points in time (e.g. blood pressure rising and falling), while column B represents onset of an event (e.g. a shock or a deep breath). Column A has values for every cell, while column B only has values at a time point where an event occurred, which represent codes for the onset of different kinds of events (e.g. 1, 2, 3, 4, 5 for 5 kinds).
What code can use the values in column B to subset data in column A (say collect all data from any time points between an event 1 and 2, and event 1 and 3, or event 1 and 4)? Basically, I'm trying to pull out the values for only certain time period segments, and store them in a cell array.
Example:
What I have:
Array A: 10, 12, 13, 20, 15, 16, 14, 9, 8, 11, 12, 15, 14
Array B: 1, 0, 2, 0, 0, 0, 1, 0, 2, 0, 1, 0, 2
*(where in Array B, 1 and 2 are events--say a showing a cue and a subject
responding to that cue--and I want the data between a 1 and a 2)*
What I want:
(New) Cell Array C: [12, 13] , [9, 8] , [15,14]
*That is, it's grabbing the data from Array A, based on what falls between
1s and 2s in Array B, and storing them into cells of Array C*
Many thanks!

Here's a way:
Find the indices of starts and ends. This can be done using strfind, which also works with numeric arrays.
Use those indices to build the result with a loop.
ind_start = strfind(B, [1 0]); % Or: ind_start = strfind(char(B+48), '10');
ind_end = strfind(B, 2); % Or: ind_end = strfind(char(B+48), '2')
result = cell(size(ind_start));
for k = 1:numel(ind_start)
result{k} = A(ind_start(k)+1:ind_end(k));
end

Related

Matlab resample time series for specific times, rather than frequencies

I have the following problem in Matlab:
I have a time series which looks like this:
size(ts) = (n,2); % with n being the number of samples, the first column is the time, the second the value.
Let's say I have:
ts(:,1) = [0, 10, 20, 30, 40];
ts(:,2) = [1, 3, 10, 6, 11];
I would like to resample the signal above to get the interpolated values at different times. Say:
ts(:,1) = [0, 1, 3, 15, 40];
ts(:,2) = ???
I had a look at the Matlab functions for signal processing but they are all only relevant for regular sampling at various frequencies.
Is there a built in function which would give me the above, or do I have to compute the linear interpolation for each new desired time manually? If so, do you have a recommendation to do this efficiently using vecotrized code (just started Matlab a month ago so still 100% at ease with this and relying on for loops a lot still).
For a bit of context, I'm using a finite difference scheme in series to investigate a problem. The output of one FD scheme is fed into the following. Due to the nature of my problem, I have to change the time stepping from one FD to the next, and my time steps can be irregular.
Thanks.
Since your data are 1-D you can use interp1 to perform the interpolation. The code would work as follow:
ts = [0, 10, 20, 30, 40; % Time/step number
1, 3, 10, 6, 11]; % Values
resampled_steps = [0, 1, 3, 15, 40]; % Time for which we want resample
resampled_values = interp1(ts(1, :), ts(2, :), resampled_step);
% Put everything in an array to match initial format
ts_resampled = [resampled_steps; resampled_values];
Or you can alternatively, following the same idea:
ts = [0, 10, 20, 30, 40; % Time/step number
1, 3, 10, 6, 11]; % Values
% Create resample array
ts_resampled = zeros(size(ts));
ts_resampled(1, :) = [0, 1, 3, 15, 40];
% Interpolate
ts_resampled(2, :) = interp1(ts(1, :), ts(2, :), ts_resampled(1, :));
You can even choose the interpolation method you want, by passing a string to the interp1 function. The methods are listed here
Note that this only work if you re-sample with time stamps within your original scope. If you want them outside you have to tell the function how to extrapolate using the key word 'extrap'. Detail here

Matlab find the maximum and minimum value for each point of series of arrays (with negative values)

lets say that we have the next series of arrays:
A = [1, 2, -2, -24];
B = [1, 4, -7, -2];
C = [3, 1, -7, -14];
D = [11, 4, -7, -1];
E = [1, 2, -3, -4];
F = [5, 14, -17, -12];
I would like to create two arrays,
the first will be the maximum of each column for all arrays,
i.e.
Maxi = [11,14,-2 -1];
the second will be the minimum of each column for all arrays
i.e.
Mini= [1,1,-17 -24];
I am trying all day, using loops, with max, and abs but I cant make it work
in my problem have a matrix (100,200), so with the above example i am trying to easily approach the problem. The ultimate goal is to get a kinda fitting of the 100 y_lines of 200 x_points. The idea is to calculate two lines (i.e. max,min), that will be the "visual" boarders of all lines (maximum and minimum values for each x). The next step will be to calculate an array of the average of these two arrays, so in the end will be a line between all lines.
any help is more than welcome!
How about this?
Suppose you stack all the row vectors , namely A,B...,F as
arr=[A;B;C;D;E;F];% stack the vectors
And then use the max(), min() and mean() functions provided by Matlab. That is,
Maxi = max(arr); % Maxi is a row vector carrying the max of each column of arr
Mini = min(arr);
Meani = mean(arr);
You just have to stack them as shown above. But if you have 100s of row vectors, use a loop to stack them into array arr as shown above.

Count unique consecutive values in Matlab

I have a data column which includes string and integer values, as well as blank cells (see below). What I would like to do is count the number of occurrences of unique string and integer values, but only for those values which are preceded by a different/blank value. Is this possible in Matlab? Many thanks.
Example:
Red, Red, Red, [blank], 2, 2, 1, 1, 1, [blank], 1, 1, [blank], Red, Red, 1
Desired output:
Red = 2,
2 = 1,
1 = 3
First find indices of the values you want to count - i.e. the first one, and those that differ from the preceding value and are non-blank. Then you need to count unique values in resulting subset. Small caveat is that you cannot simply use unique since data types as mixed. One way to get around it would be converting numbers to strings (that obviously assumes that you don't have strings which coincide with numbers). You can then use a combination of unique and accumarray to find unique values and their frequencies:
data = {'Red', 'Red', 'Red', [], 2, 2, 1, 1, 1, [], 1, 1, [], 'Red', 'Red', 1};
idx = [true, ~cellfun(#isequal, data(2:end), data(1:end-1)) & ~cellfun(#isempty, data(2:end))];
data_match = data(idx);
data_str = cellfun(#num2str, data_match, 'uni', false);
[~, ia, ic] = unique(data_str, 'stable');
values = data_match(ia)'
counts = accumarray(ic, 1)
values =
'Red'
[ 2]
[ 1]
counts =
2
1
3

How to get a regular sampled matrix in Scilab

I'm trying to program a function (or even better it it already exists) in scilab that calculates a regular timed samples of values.
IE: I have a vector 'values' which contains the value of a signal at different times. This times are in the vector 'times'. So at time times(N), the signal has value values(N).
At the moment the times are not regular, so the variable 'times' and 'values' can look like:
times = [0, 2, 6, 8, 14]
values= [5, 9, 10, 1, 6]
This represents that the signal had value 5 from second 0 to second 2. Value 9 from second 2 to second 6, etc.
Therefore, if I want to calculate the signal average value I can not just calculate the average of vector 'values'. This is because for example the signal can be for a long time with the same value, but there will be only one value in the vector.
One option is to take the deltaT to calculate the media, but I will also need to perform other calculations:average, etc.
Other option is to create a function that given a deltaT, samples the time and values vectors to produce an equally spaced time vector and corresponding values. For example, with deltaT=2 and the previous vectors,
[sampledTime, sampledValues] = regularSample(times, values, 2)
sampledTime = [0, 2, 4, 6, 8, 10, 12, 14]
sampledValues = [5, 9, 9, 10, 1, 1, 1, 6]
This is easy if deltaT is small enough to fit exactly with all the times. If the deltaT is bigger, then the average of values or some approximation must be done...
Is there anything already done in Scilab?
How can this function be programmed?
Thanks a lot!
PS: I don't know if this is the correct forum to post scilab questions, so any pointer would also be useful.
If you like to implement it yourself, you can use a weighted sum.
times = [0, 2, 6, 8, 14]
values = [5, 9, 10, 1, 6]
weightedSum = 0
highestIndex = length(times)
for i=1:(highestIndex-1)
// Get the amount of time a certain value contributed
deltaTime = times(i+1) - times(i);
// Add the weighted amount to the total weighted sum
weightedSum = weightedSum + deltaTime * values(i);
end
totalTimeDelta = times($) - times(1);
average = weightedSum / totalTimeDelta
printf( "Result is %f", average )
Or If you want to use functionally the same, but less readable code
timeDeltas = diff(times)
sum(timeDeltas.*values(1:$-1))/sum(timeDeltas)

Aggregate 3rd dimension of a 3d array for the subscripts of the first dimension

I have a 3 Dimensional array Val 4xmx2 dimension. (m can be variable)
Val{1} = [1, 280; 2, 281; 3, 282; 4, 283; 5, 285];
Val{2} = [2, 179; 3, 180; 4, 181; 5, 182];
Val{3} = [2, 315; 4, 322; 5, 325];
Val{4} = [1, 95; 3, 97; 4, 99; 5, 101];
I have a subscript vector:
subs = {1,3,4};
What i want to get as output is the average of column 2 in the above 2D Arrays (only 1,3 an 4) such that the 1st columns value is >=2 and <=4.
The output will be:
{282, 318.5, 98}
This can probably be done by using a few loops, but just wondering if there is a more efficient way?
Here's a one-liner:
output = cellfun(#(x)mean(x(:,1)>=2 & x(:,1)<=4,2),Val(cat(1,subs{:})),'UniformOutput',false);
If subs is a numerical array (not a cell array) instead, i.e. subs=[1,3,4], and if output doesn't have to be a cell array, but can be a numerical array instead, i.e. output = [282,318.5,98], then the above simplifies to
output = cellfun(#(x)mean(x(x(:,1)>=2 & x(:,1)<=4,2)),Val(subs));
cellfun applies a function to each element of a cell array, and the indexing makes sure only the good rows are being averaged.