4
votes

I'm having great difficulty coding the following in MATLAB: Suppose you have the following vector:

a   
b
c
d
e
f
g
h
...

Specifying an (even) window size, create the following matrix of dimensions L rows by n columns (example, L = 4):

a c e ...
b d f ...
c e g ...
d f h ...

Even more difficult is taking a vector of arbitrary length, specifying the number of windows, and optimizing (maximizing) the window size so less values at the end of the vector are dumped.

4
Does the window position always shift by 2 between columns? Or is that based on the window size? Or is it an additional input? Also can you please clarify what you mean by "values at the end of the vector are dumped"? Thanks!Brian L
The window position shifts by L/2. Ex. window size L = 8, shift by 4. The window size, L, is specified. Ex. If the length of the vector is 9 and L is set to 4, it is only possible to overlap three times: {a b c d} {c d e f} {e f g h} {i} (this value, i, is dumped since another complete window cannot be formed)janon128
Was any of the presented answers useful to you? If so, please take the time to accept (and possibly upvote) the best (in your opinion) answer. This will motivate people to help you in the future.angainor

4 Answers

4
votes

Create the matrix of indices into your vector. For L=4 (I assume you are overlapping by L/2), the indices are [1,2,3,4;3,4,5,6;5,6,7,8] etc. Let x = 1:L, y = L/2, the vector of indices is x+0y,x+1y,x+2y, and so on.

% let your initial data be in vector "data"
L = 4
N = floor(length(data)/(L/2))-1 % number of windows, or you specify this
mi = repmat(1:L,[N,1]) + repmat((L/2) * (0:(N-1))',[1,L]) % x + y * 0,1,2...
out = data(mi) % out is N-by-L, transpose to L-by-N if you like
4
votes

Short answer

bsxfun is your friend in this case. The following one-liner (assuming you know L and v is your vector) does what you want

v(bsxfun(@plus, [0:L-1]', 1:L/2:numel(v)-L))

Explanation

To try it out and understand it, lets have a further look. The idea is to first create a vector that determines, where the windows start in the v vector. Windows start every L/2 entries (L is even, so we can divide). But how many windows fit? We can rely on MATLAB to figure this out by saying:

start_offset = 1:L/2:numel(v)-L;

Here we just only need to specify that

  • first window is at at index 1
  • windows start every L/2 entries
  • the last window should start at least L entries before the end of the v vector. So that the last window fist in there.

Now, the rest of the example:

v = 'a':'z';
L = 4;

% indices in every output matrix column are contiguous
% and the difference between first and last is `L-1`
id1 = [0:L-1]';

% start_offset determines where in the input vector v every window starts.
% windows start every L/2 entries. The last entry that fits will start
% at some index, from which we can still use L subsequent indices to access v
start_offset = 1:L/2:numel(v)-L;

% calculate how many entries were dropped from v
% from number of elements in v subtract the largest index value used
dropped = numel(v) - (start_offset+L-1);

% window indices are created using bsxfun and singleton expansion.
% Every window's indices are given by [0:L-1] + window start index
idx = bsxfun(@plus, id1, start_offset);

v(x)

ans =

  acegikmoqsu
  bdfhjlnprtv
  cegikmoqsuw
  dfhjlnprtvx
2
votes

Here's a general way to do what you want:

1) Calculate the appropriate window width (and corresponding shift)
2) Determine the start indices of each column by iterating from 1 by the amount you want to shift the window each column, up to the final value. Make this a row vector.
3) Use bsxfun to expand this to a matrix of indices.
4) Use the indices to get the values from the original vector.

vec = 1:17; #% original data vector
num_windows = 3; #% specified number of windows
possible_window_length = 1:length(vec);
window_length = possible_window_length(find(possible_window_length +...
    (num_windows-1) * possible_window_length/2 < length(vec),1,'last'));
window_shift = floor(window_length)/2;
window_length = window_shift * 2; #% calculated window length
max_final_start_index = (length(vec)-window_length+1);
start_indices = 1:window_shift:max_final_start_index;
inds = bsxfun(@plus,start_indices,(0:window_length-1)');
soln = vec(inds); #% get the solution
num_excluded_vals = max_final_start_index - start_indices(end)
disp(soln);
num_excluded_vals =  1
disp(soln);
    1    5    9
    2    6   10
    3    7   11
    4    8   12
    5    9   13
    6   10   14
    7   11   15
    8   12   16
1
votes

There are many ways to do this in MATLAB by manipulating indices, procedural approaches, vectorized solutions, etc. Yet, I can't help but think of how simple some tasks might be, if MATLAB had a wee bit of support for functional style of programming. In that spirit, I present the following solution. Ensure that you don't already have any values in those variables at definition time.

take=@(mat,n)mat(1:n)
partition=@(mat,L)cell2mat(arrayfun(@(x)take(circshift(mat(:),-x*L/2),L),...
        0:fix((length(mat)-L)/2+1)-1,'UniformOutput',0))

Now try it with a test vector:

partition(1:10,4)

 %ans = 
 %    1     3     5     7
 %    2     4     6     8
 %    3     5     7     9
 %    4     6     8    10

The above solution discards the final values at the end of the vector that don't fit a length L after partition. You can now build up on this to handle other arrangements and figure out optimal window lengths for minimal end wastage, etc.