Compute mean value over a sliding window in MATLAB - arrays

I have a time series data or considering a real valued data of length N. I want to create sub-blocks of length k, which is the window length. The value of k can be arbitrarily chosen. This creates problem since the window size is the same across the data. I want to store each subblock in an array. But I am stuck in creating sub-blocks of the data and to include a check so that the (mod(N, nseg)) nseg must be divisible by the data length.
N = 512; %length of the time series
data = rand(N,1);
window_length = 30; %k
Nseg = floor(N/window_length) %Number of segments or blocks
Modified_Data = [mean(reshape(data,window_length,Nseg))]; %Throws error

If you have the Image Processing toolbox you could use im2col to slide a specific block size over the entire time series. Each column of the output represents the data from one of those blocks.
values = im2col(data, [window_length 1], 'distinct');
Since it looks like you just want the mean over each block, you could also use blockproc to do this.
means = blockproc(data, [window_length, 1], #(x)mean(x.data));
If you do not have the Image Processing Toolbox, you can instead use accumarray to perform this task.
means = accumarray(floor((0:(N-1)).'/window_length) + 1, data, [], #mean);
If you want to discard any data that extends beyond a number which is divisible by window_length, you can do this with something like the following:
data = data(1:(numel(data) - mod(numel(data), window_length)));
If you want overlapping data, you'll either want to use straight-up convolution (the preferred method)
means = conv(data(:), ones(5, 1)/5, 'same');
Or you can create overlapping blocks with im2col by omitting the last input.
values = im2col(data, [window_length 1]);
means = mean(values 1);

If you have R2016a+, consider using the built-in movmean function:
N = 512; %length of the time series
data = rand(N,1);
window_length = 30; %k
Modified_Data = movmean(data, window_length);
See the documentation for further details and other options.

If I understand your question correctly, it's pretty straightforward:
filter(ones(N,1)/N,1,signal)
If you think about it filtering with [1/N 1/N 1/N...1/N] is exactly calculating the localized mean...

Related

MATLAB: Improving for-loop

I need to multiply parts of a column vector with a fixed row vector. I solved this problem using a for-loop. However, I am wondering if the performance can be improved as I have to perform this kind of computation around 50 million times. Here's my code so far:
multMat = 1:5;
mat = randi(5,10,1);
windowSize = 5;
vout = nan(10,1);
for r = windowSize : 10
vout(r) = multMat * mat( (r - windowSize + 1) : r);
end
I was thinking about uisng arrayfun. However, first I don't know how to adress the cell range (i.e. the previous five cells including the current cell), and second, I am not sure if arrayfun will be any faster than using the loop?
This sliding vector multiplication you're describing is an example of what is known as convolution. The following produces the same result as the loop in your example:
vout = [nan(windowSize-1,1);
conv(mat,flip(multMat),'valid')];
If your output doesn't really need the leading NaN values which aren't overwritten in your loop then the conv expression is sufficient without concatenating the NaN elements to it.
For sufficiently large vectors this is of course not guaranteed to be as fast as you'd like it to be, but MATLAB's built-in convolution implementation is likely to be pretty close to an optimal tool for the job.

Calculating sum of array elements and reiterate for entire array in MATLAB

I have a vector A of size 7812x1 and would like to calculate the sum of fixed windows of length 21 (so 372 blocks). This should be reiterated, so that the output should return a vector of size 372x1.
I have t=7812, p=372, w=21;
for t=1:p
out = sum(A((t*w-w+1):(t*w)));
end
This code, however, does not work. My idea is that the part ((t*w-w+1):(t*w)) allows for something like a rolling window. The window is of length 21, so there is not really a need to express is with variables, yet I think it keeps some flexibility.
I've seen potentially related questions (such a partial sum of a vector), yet I'm not sure whether this would result the output desired.
Reshape into a matrix so that each block of A is a column, and compute the sum of each colum:
result = sum(reshape(A, w, []), 1);
Following your idea of using a rolling/moving window (requires Matlab 2016a or later):
t = 7812; w = 21; % your parameters
A = rand(t,1); % generate some test data
B = movsum(A,w); % the sum of a moving window with width w
out = B(ceil(w/2):w:end); % get every w'th element

Matlab: Difference bettween two different sized arrays

Is it possible to find the difference beetwen two arrays of different size?
My problem is that I have two arrays, that scaled are pretty similar and I need the error in each point.
The data look like this:-
Yaw data is much bigger than Yaw Ref.
You could take a very naive approach and simply pad each element of the reference array. That is fairly simple to do:
n = length(yaw)/length(yaw_ref);
yaw_ref_pad = zeros(length(yaw), 1);
for j = 1:length(yaw_ref)-1
yaw_ref_pad((n*j):(n*(j+1)) = yaw_ref(j);
end
You could also do something more adaptive, which may or may not be what you want. This approach uses the derivatives to determine where the padded reference should switch. This might be considered a bit circular, since your system looks like an overdamped PID system and this uses the output to seed the input.
yaw_ref_pad = zeros(length(yaw), 1);
[x, peaks] = findpeaks(diff(yaw));
for j = 1:length(peaks)-1
yaw_ref_pad(peaks(j):peaks(j+1)) = yaw_ref(j);
end
Either way, after filling yaw_ref_pad, your result is simply
error = yaw_ref_pad - yaw;

Increasing luminosity does not produce desired effect

cvCvtColor(img,dst,CV_RGB2YCrCb);
for (int col=0;col<dst->width;col++)
{
for (int row=0;row<dst->height;row++)
{
int idxF = row*dst->widthStep + dst->nChannels*col; // Read the image data
CvPoint pt = {row,col};
temp_ptr2[0] += temp_ptr1[0]* 0.0722 + temp_ptr1[1] * 0.7152 +temp_ptr1[2] *0.2126 ; // channel Y
}
}
But the result is this:
Please assist where am i going wrong?
There is a lot to say about this code sample:
First, you are using the old C-style API (IplImage pointers, cvBlah functions, etc), which is obsolete and more difficult to maintain (in particular, memory leaks are introduced easily), so you should consider using the C++-style structures and functions (cv::Mat structure and cv::blah functions).
Your error is probably coming from the instruction cvCopy(dst,img); at the very beginning. This fills your input image with nothing just before you start your processing, so you should remove this line.
For maximum speed, you should invert the two loops, so that you first iterate over rows then over columns. This is because images in OpenCV are stored row-by-row in memory, hence accessing the images by increasing column is more efficient with respect to the cache usage.
The temporary variable idxF is never used, so you should probably remove the following line too:
int idxF = row*dst->widthStep + dst->nChannels*col;
When you access image data to store the pixels in temp_ptr1 and temp_ptr2, you swapped the positions of the x and y coordinates. You should access the image in the following way:
temp_ptr1 = &((uchar*)(img->imageData + (img->widthStep*pt.y)))[pt.x*3];
You never release the memory allocated for dst, hence introducing a memory leak in your application. Call cvReleaseImage(&dst); at the end of your function.

Summing blocks of numbers in a vector in matlab

I need to sum consecutive 96 value blocks in a vector of n (in one case 14112) values. The background is that the values are 15-min temperature measurements and I want to average 96 at a time (1 to 96, 96+1 to 2*96 ... n*96+1 to (n+1)*96) to produce a daily average. This could of course be done in a loop stepping 96 but my question is if there is a more efficient way to accomplish this in Matlab.
By using reshape and mean:
data = randn(1,14112); % example data. Row vector
m = 96; % block size. It is assumed that m divides length(data)
result = mean(reshape(data,m,[]));
As #Dan points out, if the number of elements is not a multiple of the block size some padding is necessary. The following code, due to him, does the necessary padding in the last block while keeping the mean of that block. Thanks also to #DennisJaheruddin for his sugggestion not to modifiy original variable:
data = randn(1,14100); % example data. Row vector
m = 96; % block size
n = length(data);
result = mean(reshape([data repmat(mean(data(n-mod(n,m)+1:n)), 1, m - mod(n, m))], m, []));
Here is an alternate way to nicely deal with the problem, it also works if the lenght of the data is not a nice multiple of the window size:
data = randn(1,14112);
w = 96;
N = numel(data);
M = NaN(w,ceil(N/w));
M(1:N) = data;
nanmean(M)
If you don't want to include partial days at the end, use fix instead of ceil.

Resources