Matlab resample time series for specific times, rather than frequencies - matlab

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

Related

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.

Creating 2D Matrix from Vector

I currently have a vector called assignments (ex. [1, 1, 3, 2]) of size NUM_PATCHES. I want to create a 2D matrix feat_vecs of dimensions [NUM_CLUSTERS, NUM_PATCHES] such that the matrix looks like this:
[1, 1, 0, 0
0, 0, 0, 1
0, 0, 1, 0]
Therefore, if we have assignments(i), I want the corresponding column i and row assignments(i) to have a value of 1.
I am currently accomplishing this using this code:
feat_vecs = full(sparse(assignments, 1:NUM_PATCHES, ones(NUM_PATCHES, 1), NUM_CLUSTERS, NUM_PATCHES));
i have also tried using sub2ind using this code:
feat_vecs = zeros(NUM_CLUSTERS, NUM_PATCHES);
feat_vecs(sub2ind([NUM_CLUSTERS, NUM_PATCHES], assignments, 1:NUM_PATCHES)) = 1;
However, this second piece of code seems to be a bit slower.
>> tic;
>> feat_vecs = full(sparse(assignments, 1:NUM_PATCHES, ones(NUM_PATCHES, 1), NUM_CLUSTERS, NUM_PATCHES));
>> toc;
Elapsed time is 0.011319 seconds.
>> tic;
>> feat_vecs = zeros(NUM_CLUSTERS, NUM_PATCHES);
>> feat_vecs(sub2ind([NUM_CLUSTERS, NUM_PATCHES], assignments', 1:NUM_PATCHES)) = 1;
>> toc;
Elapsed time is 0.014425 seconds.
I am running this piece of code thousands of times, so a small difference in runtime can quickly add up. I am wondering if there is a faster or more efficient way to accomplish this task.

Expand an array by filling in with current values in MATLAB

I have a fairly simple issue and I just want to know if there's an easy way to do it in MATLAB (i.e. a function to do this rather than writing out loops or something myself).
Let's say I have a timeseries where Time is 1:1:1000 and Data is 2 * (1:1:1000) and I want to expand the array by making the Time and Data vector finer. Let's say that I want Time to be 1:0.1:1000 and Data to be 2 * (1:0.1:1000). Is there an easy way to tell MATLAB that to repeat the values of each vector 10 times (from 1 / 0.1 = 10) so that I can have something like this?:
Time: [1, 2, 3, 4, ...]
Data: [2, 4, 6, 8, ...]
to:
Time: [1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, ...]
Data: [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, ...]
You can use combination of reshape() and repmat() as follow:
Data = [2, 4, 6, 8, ...] % As stated in the question.
Data = reshape(repmat(Data, 10, 1), 1, []);
This is more time-efficient than the others like kron() or combination of sort() and repmat().
Two simulations were done and the results are shown in the following figures.
First: Simulation time vs. length of Data. Here I used N=100 instead of 10.
Second: Simulation time vs. repetition factor. Length of Data is 10000.
So you can select the best one according to the simulation results.
As seb proposed, you can use the function repmat. Here what I would do:
Data = [2, 4, 6, 8, ...];
Data = sort(repmat(Data,1,10));
You can use repmat
interval_size = 10;
Data = 2*(1:1:1000);
out_data = repmat(Data,interval_size,1);
out_data = out_data(:)';
Example Data:
time=1:50
data=2:2:100
t2=1:.1:50.9
For time=1:n this is very simple:
data(:,floor(t2))
If your original data has another time scale, use this:
[a,b]=ismember(floor(t2),time)
data(:,b)

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)

Populating all the values of a vector with values from another vector at places from still another vector [duplicate]

This question already has answers here:
Element-wise array replication according to a count [duplicate]
(4 answers)
Closed 8 years ago.
I have two vectors representing the edges and levels some continuous data (this is simulated at the moment).
edges = [50, 120, 170, 200, 220, 224, 250]
levels = [24,3,30,0,36,0]
How would I create a vector that has 24 for the first 50 entries, 3 for the subsequent 120 etc?
I've tried
psd = zeros(1,250)
psd(edges) = levels
but this just puts a single value at the relevant position - it's not quite what I want.
Your description and code don't quite match. Do you want psd to have 250 elements or 1234 (sum(edges), as your use of subsequent would imply)? If it's the latter, you can simply modify edges = cumsum(edges). Secondly, you don't have enough levels for the given edges.
Here's a solution without the use of loops.
edges = [50, 120, 170, 200, 220, 224, 250];
levels = [24,3,30,0,36,0,nan]; % padded with nan for equal length
idxs = length(levels) - sum(bsxfun(#(x,y) x < y,1:max(edges),edges'+1))+1;
pds = levels(idxs)
Or even simpler:
idxs = zeros(1,max(edges));
idxs(edges(1:end-1)+1) = 1;
psd = levels(cumsum(idxs)+1)
Here is a little solution, if edges is really the edges of your intervals:
Expand the vector levels with 0 as a first element:
levels = [0, 24, 3, 30, 0, 36, 0];
Then you can do the following:
psd = zeros(1,250);
psd(edges(2:end)-1) = diff(levels);
psd = cumsum(psd);
You put at the interval limits the offset betwwen two consecutive values, 0 elsewhere. When summing up, you have what you expect.
Involves a loop but it should be OK. Also, your edges and levels need to be of equal length.
v = [];
for i = 1:numel(edges)
v = [v;level(i)*ones(edges(i),1)];
end
Here's a more efficient version which takes care of the allocation overhead.
v = zeros(sum(edges),1);
c = [0 cumsum(edges)];
for i = 1:numel(edges)-1
v( c(i)+1:c(i+1) ) = levels(i)*ones(edges(i),1);
end
Just remember ; loops aren't always evil in today's MATLAB. Sometimes, it's the simplest (and clearest) solution.
You can use this run-length decoding utility FEX rude(), which implements the approach showed by Bentoy13:
% example inputs
edges = [2, 3, 1];
levels = [24,3,30];
the result
rude(edges, levels)
ans =
24 24 3 3 3 30
Inspired by an answer by gnovice you can use this:
psd = levels(cumsum(sparse(1,cumsum([1 edges(1:end-1)]),1,1,sum(edges))));
To make it easier you can create an anonymous function and resuse it instead:
populate = #(L,E) L(cumsum(sparse(1,cumsum([1 E(1:end-1)]),1,1,sum(E))));
psd = popultae(levels, edges);