拟合两条曲线

机器算法验证 曲线
2022-03-18 15:04:05

我正在尝试确定两条曲线之间的拟合(示例如下)。两条曲线都在这里绘制为一堆 XY 数据点(不是函数)。

这些曲线代表了两架飞机滑行的轨迹,我试图弄清楚它们平均相距多远。(轴在 x/y 位置,以米为单位)

我已经完成了相关性和 RMSE,但这些都不是我真正想要的——两架飞机以不同的速度行驶,因此一条曲线的数据点比另一条曲线多得多。所以 RMSE 对时间很敏感,而我希望偏差与时间无关。

我的下一个想法是进行某种整合,但我不确定这将如何工作,因为曲线经常交叉。

正如你所看到的,曲线非常相似,所以我希望得到一个小的结果......可能在 0-5 米左右。

我应该在这里做什么样的分析?

在此处输入图像描述

转弯特写: 在此处输入图像描述

2个回答

这有点像我必须在实验室进行的动物追踪数据分析。我的反应是这样的:

首先按照@Iterator 的建议定义一个线性化轨道。我通过定义具有 3 到 20 个控制点的样条曲线来做到这一点。您可以通过所有数据拟合样条曲线,也可以使用绝对的东西,例如滑行跑道的物理形状,或者教科书般完美的滑行会产生的最佳路径。无论您选择什么,我们都将其称为参考路径

然后对该样条线进行密集采样 - 沿着样条线从头到尾均匀分布找到 100,000 个左右的点。

接下来,对于每个时间点和每个轨迹,确定两件事:(x) 沿参考路径的点的标识,该点最接近该时间点平面的 XY 位置,以及 (y) 欧几里得距离在瞬时数据点和最近的样条点之间。将 y 绘制为 x 的函数为您提供平面和参考路径之间的距离图,按该路径的距离。

如果您将参考路径定义为通过平面 A 轨迹的样条曲线,并针对该路径绘制平面 B 的上述图,您将获得平面之间的距离,作为它们沿轨道的路线的函数,与时间无关。

这是一些可以解决问题的注释代码。在我的电脑上使用这里的测试数据。


% 脚本将 2 条路径之间的距离确定为函数
沿第一条路径的距离百分比
%
% 路径 1 用于拟合样条曲线。该样条被密集插值
% 对于路径 2 上的给定点,搜索 path1 插值点
% 表示欧几里得距离最小的那个。到的距离
% 最近的 Path1 插值点 ALONG 路径 1 是路径 2 点'
%“参考路径距离”,与插值之间的距离
% 点和路径 2 点是“参考路径偏差”
%
% 因为路径 1 上的点不是从
% 路径的起点到终点,以适应平滑的样条曲线
% 路径 1,我让用户单击路径 1 上的样条控制点。A
% 临时样条适合用户的点击点,而临时样条
% spline 用于将路径 1 的数据分解为小数据组。
每组的 % 质心作为构建路径的控制点 1
% 样条。

%% 加载数据。path1 和 path2 都是 2xn [x_data; y_data] %%
加载 pos_data.mat path1 path2;

%% 绘制原始数据并从用户那里获取样条点 %%
数字; 情节(路径1(1,:),路径1(2,:),'b');% 第一条路径
坚持,稍等; 情节(路径2(1,:),路径2(2,:),'r');% 第二条路径
[spl_x, spl_y] = getpts(); % 鼠标点击定义样条曲线
user_path = [spl_x'; spl_y']; % 重新排列为与path1,2相同的格式

%% 从用户点创建样条 %%
n_xx = 100;% n_xx 临时样条的插值点
n_x = 大小(用户路径,2);% n_x 个样本,每个样本 2 个值
xx_t = linspace(0,1,n_xx); % 插值
x_t = linspace(0,1,n_x); % 我们的时间参数 fn 的参数
yy_t = spline(x_t,user_path,xx_t); % yy 是沿路径在 xx 处的点
情节(yy_t(1,:),yy_t(2,:),“.b”,“线宽”,4);

%% 通过最近的 tmp 样条插值将 path1 点分成组 %%
% 对于每个 path1 点,找到最近的临时样条点
TRI = delaunay(yy_t(1,:), yy_t(2,:));
index = dsearch(yy_t(1,:), yy_t(2,:), TRI, path1(1,:), path1(2,:));
path1_x = 零(2,n_xx);% 为每个 path1 点组制作 1 个 path1 样条控制点

% 路径 1 中的点有 n_xx 个 bin。确定 n_xx 质心
落入这些箱中的点组的百分比。
对于 n = 1:n_xx
    path1_x(:,n) = [平均值(path1(1, index==n)); ...
                     平均值(路径1(2,索引==n))];
结尾

%% 使用刚刚获得的质心作为“path1 spline”的控制点。%%
n_xx = 1000; % 我们将密集采样 path1 样条
n_x = 大小(path1_x,2); % 虽然我们只有 50 个用于路径 1 样条的控制点
xx_p1 = linspace(0, 1, n_xx); % 插值到 path1 样条曲线的位置
x_p1 = linspace(0, 1, n_x); % 参数:沿临时样条的距离
yy_p1 = 样条线(x_p1,path1_x,xx_p1);% 样条沿路径 1 的 x&y 坐标
数字; 情节(路径1(1,:),路径1(2,:),'。','MarkerSize',10);
坚持,稍等; 情节(yy_p1(1,:),yy_p1(2,:),'-');

%% 通过为每个 path2 点找到沿 path1 样条曲线的最近点来“线性化”路径 2。%%
TRI = delaunay(yy_p1(1,:), yy_p1(2,:));
index = dsearch(yy_p1(1,:), yy_p1(2,:), TRI, path2(1,:), path2(2,:));

path2_dist_along = xx_p1(1,index); 每个 path2 点沿 path1 样条线的 % 距离
                                  % 只是
                                  % 路径 1 样条

% 偏差是每个 path2 点与其之间的欧几里得距离
% 最近的 path1_spline 对应                                 
path2_deviance = sqrt((path2(1,:) - yy_p1(1,index)).^2 + (path2(2,:) - yy_p1(2,index)).^2);

数字; 情节(path2_dist_along,path2_deviance,'。');

我的路径并不好,甚至像你的一样:/动物追踪现状。因此,有一种变通方法可以将样条曲线拟合到有点混乱的原始数据上。

在 path1 和 path2 上绘制 x 和 y 位置

这是脚本的输出。

路径偏差作为沿路径 1 的距离的函数

注意:如果将其绘制为折线图而不是散点图,您会看到点沿 x 轴的顺序不正确,并且 x 轴的采样不均匀。我认为这可以通过插值和平滑的某种组合来解决,但解决方案可能取决于您希望输出格式的确切方式,因此我没有对其进行编码。

我试图使代码清晰,但如果有什么令人困惑的地方,请告诉我。有趣的问题,谢谢。

我的建议是将点重新缩放为弧长(曲线)的比例。此时,您可以查看插值,例如弧长的 (0,0.01, ..., 1.00) 并比较相关性等。

然而,一个更有趣的问题可能是运动梯度之间的关系,尤其是靠近转弯处。我认为其中的情节可能非常有趣。