我有两个物理对象。"我用两个不同的阵列代表他们的位置。
•对象1仅在xy平面中移动
•对象2在所有三个物理维度上移动
目标:对四个for
循环进行矢量化而不会扭曲数据。此外,目的是对对象1的所有可能值执行此操作以与对象2进行比较。
以下是代码段:
Npos = 21;
Nsam = 200;
% dummy initialisation
AX = rand(1, Npos);
AY = zeros(1, Npos);
AZ = rand(1, Npos);
Bx = rand(Nsam);
By = rand(Nsam);
Bz = rand(Nsam);
for qx = 1 : Npos
for yx = 1 : Npos
for zx = 1 : Nsam
for cx = 1 : Nsam
Tx2Array( qx, yx, zx, cx ) = sqrt( ( AX( qx ) - Bx( zx, cx ) ).^2 + ( AY( yx ) - By( zx, cx ) ).^2 + ( AZ( yx ) - Bz( zx, cx ) ).^2 );
end
end
end
end
% Result is a 21 x 21 x 200 x 200 matrix filled with all real numbers
图例
AX,AY,AZ是1 x 21个数组,代表对象1的(x,y = 0,z)
AY全部为零,但仍然包含可读性(因此没有第五个循环!)
Bx,By,Bz都是200 x 200数组,代表对象2的(x,y,z)
Npos = 21; Nsam = 200;
上面使用的公式是:
sqrt( (a1-b1)^2 + (a2-b2)^2 + (a3-b3)^2 )
答案 0 :(得分:3)
如果您有统计工具箱,则可以使用pdist2计算对象1的每个坐标与对象2的每个坐标之间的距离:
[X1, Z1] = ndgrid(AX(:), AZ(:)); % X1 and Z1 will be 21x21
D = pdist2([X1(:), zeros(size(X1(:))), Z1(:)], [Bx(:), By(:), Bz(:)]);
在这种情况下,输出将是441 x 40,000
数组,其中D(i, j)
为您提供对象1的点i
与对象2的点j
之间的距离,两者均使用线性索引。
答案 1 :(得分:1)
您可以通过将zx
和cx
替换为:
来避免使用内部循环,如下所示:
Tx2Array = zeros(Npos, Npos, Nsam, Nsam); % preallocate memory
for qx = 1 : Npos
for yx = 1 : Npos
Tx2Array( qx, yx, :, : ) = sqrt( ( AX( qx ) - Bx( :, : ) ).^2 + ( AY( yx ) - By( :, : ) ).^2 + ( AZ( yx ) - Bz( :, : ) ).^2 );
end
end
通过这种方式,最大尺寸被矢量化。因此,最大的改进已经完成。
通过将B*
转换为4D并为A*
矩阵生成网格,您甚至可以删除所有for循环,如下所示:
[AX_, AZ_] = meshgrid(AX, AZ);
AX_ = AX_';
AZ_ = AZ_';
AY_ = zeros(Npos);
Bx_(1, 1, :, :) = Bx;
By_(1, 1, :, :) = By;
Bz_(1, 1, :, :) = Bz;
Tx2Array2 = sqrt( ( AX_ - Bx_ ).^2 + ( AY_ - By_ ).^2 + ( AZ_ - Bz_ ).^2 );
您可以使用以下检查检查结果是否相同:
max(max(max(max(abs(Tx2Array - Tx2Array2))))) < eps
答案 2 :(得分:1)
如果数组已正确初始化,您的任务将非常简单:
使用正确的尺寸初始化数组
AX = rand( Npos,1);
AY = zeros(1, Npos);
AZ = rand(1, Npos);
Bx = rand(1,1,Nsam,Nsam);
By = rand(1,1,Nsam,Nsam);
Bz = rand(1,1,Nsam,Nsam);
然后在MATLAB r2016b / Octave中你可以简单地写:
Tx2Array = sqrt( ( AX - Bx ).^2 + ( AY - By ).^2 + ( AZ - Bz ).^2 );
在r2016b之前,您可以使用bsxfun:
Tx2Array = sqrt(bsxfun(@plus,bsxfun(@plus,bsxfun(@minus,AX , Bx).^2,bsxfun(@minus,AY , By).^2),bsxfun(@minus,AZ , Bz).^2));