我有一个矢量,我希望它向前重复n次,向后重复n次,但是对角线。
例如,我有矢量:
x= [0 0 1 1 0 0]
,
并且需要一个大小为6x5的矩阵,如下所示:
1 0 0 0 0
1 1 0 0 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 1
0 0 0 0 1
这意味着向量[0 0 1 1 0 0]
(转置)位于中间,我想要一个矩阵,当向左移动时,元素会循环移动到顶部向左转。类似地,当向右移动时,对于您向右移动的每个班次,元素将循环向下移动到底部。因此,第二列将是[0 1 1 0 0 0]
,其中元素以循环方式向左移动一次,然后第一列将是[1 1 0 0 0 0]
,其中我们将所有元素向左移动两次相对于中间和第二列一次。
同样,第四列将是[0 0 0 1 1 0]
,这意味着相对于中间列,我们将所有元素以循环方式向右移动一次,然后最后一列将是[0 0 0 0 1 1]
我们在哪里将所有元素相对于中间向右移动两次,相对于第四列向右移动一次。
答案 0 :(得分:4)
convmtx
需要信号处理工具箱才能计算结果。虽然路易斯的答案非常好,但我可以建议一种不依赖于工具箱的方法吗?
n = 2;
ind = mod(bsxfun(@plus, (0:numel(x)-1).', n:-1:-n), numel(x)) + 1;
y = x(ind);
或者,如果您不想要中间变量:
n = 2;
y = x(mod(bsxfun(@plus, (0:numel(x)-1).', n:-1:-n), numel(x)) + 1);
对于x = [0 0 1 1 0 0];
,我们得到:
y =
1 0 0 0 0
1 1 0 0 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 1
0 0 0 0 1
此代码的解释非常简单。 n
表示您希望重复"的次数。左侧和右侧的向量x
,其中每列向上或向下循环移动元素,具体取决于您前进的矩阵中的哪个方向。
第二行代码是最令人生畏的。让我们从bsxfun(...)
电话开始:
bsxfun(@plus, (0:numel(x)-1).', n:-1:-n))
这会创建一个numel(x) x (2*n + 1)
矩阵,其中每列只是向量(0:numel(x)-1)
,但是有一个常量值。从第一列开始,我们将n
添加到(0:numel(x)-1)
,然后我们将n-1
添加到(0:numel(x)-1)
的第二列,直到我们到达(0:numel(x)-1)
的中间位置} 通过它自己。通过中间后,我们使用常量减去向量,从-1
列n+1
开始,-2
为n+2
专栏直到结束。我们得到n = 2
的结果是:
ans =
2 1 0 -1 -2
3 2 1 0 -1
4 3 2 1 0
5 4 3 2 1
6 5 4 3 2
7 6 5 4 3
在一个理想的世界中,我们基本上会使用这个矩阵来索引我们的向量,以获得我们想要的矩阵。中间左侧的列通过指定前进1的索引逐步访问元素,结果是将元素移向矩阵的顶部。类似地,通过指定延迟1的索引并且对于结果,中间渐进访问元素右侧的列是将元素移向矩阵的底部。
不幸的是,我们的负值和值都超过了矢量的长度。最重要的是,MATLAB开始索引为1.因此,您将不得不使用一些环绕逻辑来确保一旦我们超过向量的长度或产生索引的负值,我们应该回过头来 1 而不是0或向量的长度而不是-1。因此,我们可以简单地放置一个mod
(模数/余数)运算,以x
中的元素总数为界,然后在整个矩阵中加1后,我们可以将索引限制在1和现在将我们带到完成的第二行代码的元素总数:
>> ind = mod(bsxfun(@plus, (0:numel(x)-1).', n:-1:-n), numel(x)) + 1
ind =
3 2 1 6 5
4 3 2 1 6
5 4 3 2 1
6 5 4 3 2
1 6 5 4 3
2 1 6 5 4
最后一步是简单地使用此矩阵索引到矢量中以实现所需的输出矩阵:
>> y = x(ind)
y =
1 0 0 0 0
1 1 0 0 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 1
0 0 0 0 1
答案 1 :(得分:2)