我正在Matlab中使用未公开的contours
函数来获取将R^2
映射到R
的函数的零轮廓。函数contours()
调用contourc()
以获取数组索引为零的轮廓,然后contours()
执行线性插值以将(M,N)
数组索引转换为(Y,X)
数据坐标。这样效果很好,并给出了零轮廓,该轮廓实际上对机器精度是精确的。但是,尝试沿着该零轮廓进行插值以获得其他点失败了,这显然是因为插值点与真实零轮廓的偏差很小。对于预期的应用程序,产生的错误太大。
作为一个简单的示例,可以计算peaks
函数的零轮廓,沿轮廓计算函数值,然后在沿轮廓插值的新点计算函数值。 eps(max(Z(:))
找到的点的最大误差大约为countours/countourc
,插值点的最大误差大约高十个数量级。
% compute the zero contours; keep part of one contour
[X,Y,Z] = peaks(999);
XY0 = contours(X, Y, Z, [0 0]);
XY0 = XY0(:,140:(XY0(2,1)+1)); % keep only ascending values in the first contour for interpolation
% interpolate points along the zero contour
x2y = griddedInterpolant(XY0(1,:), XY0(2,:), 'linear','none');
X0i = linspace(XY0(1,1), XY0(1,end), 1e4);
Y0i = x2y(X0i);
% compute values of the function along the zero contour
Zi = interp2(X,Y,Z, XY0(1,:), XY0(2,:), 'linear', NaN);
Z0i = interp2(X,Y,Z, X0i, Y0i, 'linear', NaN);
% plot results
figure;
subplot(1,3,1); plot(XY0(1,:), XY0(2,:), '.'); hold on; plot(X0i, Y0i, 'Linewidth',1);
xlabel('X_0'); ylabel('Y_0'); title('(X_0,Y_0), (X_{0i},Y_{0i})');
subplot(1,3,2); plot(XY0(1,:), Zi, '.');
xlabel('X_0'); ylabel('Z_0'); title('f(X_0,Y_0)');
subplot(1,3,3); plot(XY0(1,:), Zi, '.'); hold on; plot(X0i, Z0i, '.');
xlabel('X_0'); ylabel('Z_0'); title('f(X_{0i},Y_{0i})');
误差几乎可以肯定是因为插值并不真正遵循零轮廓(即在每个点具有相同的切线,曲率以及实际上所有更高的导数)。因此,每个插补点与零轮廓的路径有很小的偏差。对于所有测试的插值方法都是如此。如果零轮廓的功能形式是已知的,则可以使功能适合零轮廓,这将可能给出令人满意的结果。但是,对于激发这个问题的应用程序,零轮廓的解析解决方案是不可能的。
鉴于该任务的插值不足,如何获得沿零轮廓的新点?这些点应使函数的值与contourc
返回的点集一样接近零。全局提高网格分辨率不是一种选择,因为内存和计算费用会随分辨率的平方增加。在零轮廓的连续短间隔内以迭代方式在高分辨率下进行本地采样是一种选择,但要花一些时间才能实现,而且我不知道要执行此任务的现有代码(例如,在FEX中)。另外,由于contourc
是封闭源代码,因此不能选择使其适应此任务。
答案 0 :(得分:0)
我解决了这个问题,方法是将内插的(X,Y)
值作为真实零轮廓的近似值,并相对于表面侧翼的Y
值重新插入每对的Z
坐标为了找到Y
对Z=0
对的(X,Y
坐标,近似零。这样,可以保持插值X
的均匀间距。
对于每个(iX,iY)
对,其中iX
和iY
表示插值点的X
和Y
坐标网格的(分数)数组索引沿着零轮廓,在iY
尺寸(即{{1})侧翼的位置(在Z
处),相对于Y
的值重新插值(iX,floor(iY))
}和(iX,ceil(iY))
。这些侧翼点的Z
值本身是通过在这些点执行Z
的双线性插值而获得的。
重新插值后,误差的大小与contourc
/ contours
最初返回的点的大小相同。