英文:
Performing an "online" linear interpolation
问题
我有一个问题,需要对从传感器获取的一些数据进行线性插值(它实际上是位置数据,但数据的性质并不重要)。我现在在Matlab中进行这个操作,但由于最终将将此代码迁移到其他语言,我希望尽可能保持代码简单,不使用任何复杂的Matlab特定/内置函数。
我的实现初始看起来还可以,但是当我将我的工作与Matlab的内置interp1函数进行对比时,似乎我的实现并不完美,我不知道为什么。以下是我在已经完全收集的数据集上使用的代码,但当我循环遍历数据时,我表现得好像只有当前样本和上一个样本,这反映了我最终将面临的问题。
%创建一些虚拟数据
np = 109; % x和y的数据点数
x_data = linspace(3, 98, np) + (normrnd(0.4, 0.2, [1, np]));
y_data = normrnd(2.5, 1.5, [1, np]);
%定义数据将进行插值的查询点
qp = [1:100];
kk = 2; %索引数据
cc = 1; %索引查询点
qpi = qp(cc); %qpi是循环中的当前查询点
y_interp = qp * nan; %这将保存我们的解决方案
while kk <= length(x_data)
kk = kk + 1; %更新数据计数器
%执行在线插值
if cc < length(qp) - 1
if qpi >= y_data(kk - 1) %查询点当然必须位于x_data的当前值和下一个值之间
y_interp(cc) = myInterp(x_data(kk - 1), x_data(kk), y_data(kk - 1), y_data(kk), qpi);
end
if qpi > x_data(kk) %如果当前查询点已经大于当前样本,请更新样本
kk = kk + 1;
else %否则,更新查询点以确保它在下一次迭代的样本之间
cc = cc + 1;
qpi = qp(cc);
%如果x_data的变化大于查询点的分辨率,类似上面的更新将无法工作。在这种情况下,我们必须滞后数据
if qpi < x_data(kk)
kk = kk - 1;
end
end
end
end
%获取正确的插值
y_interp_correct = interp1(x_data, y_data, qp);
%绘制两种解决方案以显示差异
figure;
plot(y_interp, 'displayname', 'manual-solution'); hold on;
plot(y_interp_correct, 'k--', 'displayname', 'matlab solution');
leg1 = legend('show');
set(leg1, 'Location', 'Best');
ylabel('interpolated points');
xlabel('query points');
请注意,“myInterp”函数如下所示:
function yi = myInterp(x1, x2, y1, y2, qp)
%线性插值函数y(x)在查询点qp上
yi = y1 + (qp - x1) * ((y2 - y1) / (x2 - x1));
end
这是显示我的实现不正确的图表:
有人能帮助我找到错误在哪里吗?为什么?我怀疑与确保查询点位于前一个和当前x样本之间有关,但我不确定。
英文:
I have a problem where I need to do a linear interpolation on some data as it is acquired from a sensor (it's technically position data, but the nature of the data doesn't really matter). I'm doing this now in matlab, but since I will eventually migrate this code to other languages, I want to keep the code as simple as possible and not use any complicated matlab-specific/built-in functions.
My implementation initially seems OK, but when checking my work against matlab's built-in interp1 function, it seems my implementation isn't perfect, and I have no idea why. Below is the code I'm using on a dataset already fully collected, but as I loop through the data, I act as if I only have the current sample and the previous sample, which mirrors the problem I will eventually face.
%make some dummy data
np = 109; %number of data points for x and y
x_data = linspace(3,98,np) + (normrnd(0.4,0.2,[1,np]));
y_data = normrnd(2.5, 1.5, [1,np]);
%define the query points the data will be interpolated over
qp = [1:100];
kk=2; %indexes through the data
cc = 1; %indexes through the query points
qpi = qp(cc); %qpi is the current query point in the loop
y_interp = qp*nan; %this will hold our solution
while kk<=length(x_data)
kk = kk+1; %update the data counter
%perform online interpolation
if cc<length(qp)-1
if qpi>=y_data(kk-1) %the query point, of course, has to be in-between the current value and the next value of x_data
y_interp(cc) = myInterp(x_data(kk-1), x_data(kk), y_data(kk-1), y_data(kk), qpi);
end
if qpi>x_data(kk), %if the current query point is already larger than the current sample, update the sample
kk = kk+1;
else %otherwise, update the query point to ensure its in between the samples for the next iteration
cc = cc + 1;
qpi = qp(cc);
%It is possible that if the change in x_data is greater than the resolution of the query
%points, an update like the above wont work. In this case, we must lag the data
if qpi<x_data(kk),
kk=kk-1;
end
end
end
end
%get the correct interpolation
y_interp_correct = interp1(x_data, y_data, qp);
%plot both solutions to show the difference
figure;
plot(y_interp,'displayname','manual-solution'); hold on;
plot(y_interp_correct,'k--','displayname','matlab solution');
leg1 = legend('show');
set(leg1,'Location','Best');
ylabel('interpolated points');
xlabel('query points');
Note that the "myInterp" function is as follows:
function yi = myInterp(x1, x2, y1, y2, qp)
%linearly interpolate the function value y(x) over the query point qp
yi = y1 + (qp-x1) * ( (y2-y1)/(x2-x1) );
end
And here is the plot showing that my implementation isn't correct
Can anyone help me find where the mistake is? And why? I suspect it has something to do with ensuring that the query point is in-between the previous and current x-samples, but I'm not sure.
答案1
得分: 2
您的代码问题在于有时使用超出界限 x_data(kk-1)
和 x_data(kk)
的值来调用 myInterp
,这会导致无效的外推结果。
您循环遍历 kk
而不是 cc
的逻辑对我来说非常令人困惑。我会使用一个简单的 for
循环来遍历 cc
,这些是您要插值的点。对于这些点中的每一个,如果必要,前进 kk
,以使 qp(cc)
位于 x_data(kk)
和 x_data(kk+1)
之间(如果您喜欢,也可以使用 kk-1
和 kk
,只需初始化 kk=2
以确保 kk-1
存在,我只是觉得从 kk=1
开始更直观)。
为了简化这里的逻辑,我限制了 qp
中的值在 x_data
的限制内,这样我们就不需要测试以确保 x_data(kk+1)
存在,也不需要测试 x_data(1)<qp(cc)
。如果您愿意,可以添加这些测试。
这是我的代码:
qp = [ceil(x_data(1)+0.1):floor(x_data(end)-0.1)];
y_interp = qp*nan; % 这将保存我们的解决方案
kk=1; % 索引数据
for cc=1:numel(qp)
% 将 kk 前进到我们可以进行插值的位置
% (这个循环保证不会越界,因为 x_data(end)>qp(end),
% 但如果在循环之前不确保这一点,则需要进行调整)
while x_data(kk+1) < qp(cc)
kk = kk + 1;
end
% 执行在线插值
y_interp(cc) = myInterp(x_data(kk), x_data(kk+1), y_data(kk), y_data(kk+1), qp(cc));
end
正如您所看到的,这种方式的逻辑要简单得多。结果与 y_interp_correct
完全相同。内部的 while x_data...
循环具有与您的外部 while
循环相同的目的,是您从数据源处读取数据的地方。
英文:
The problem in your code is that you at times call myInterp
with a value of qpi
that is outside of the bounds x_data(kk-1)
and x_data(kk)
. This leads to invalid extrapolation results.
Your logic of looping over kk
rather than cc
is very confusing to me. I would write a simple for
loop over cc
, which are the points at which you want to interpolate. For each of these points, advance kk
, if necessary, such that qp(cc)
is in between x_data(kk)
and x_data(kk+1)
(you can use kk-1
and kk
instead if you prefer, just initialize kk=2
to ensure that kk-1
exists, I just find starting at kk=1
more intuitive).
To simplify the logic here, I'm limiting the values in qp
to be inside the limits of x_data
, so that we don't need to test to ensure that x_data(kk+1)
exists, nor that x_data(1)<pq(cc)
. You can add those tests in if you wish.
Here's my code:
qp = [ceil(x_data(1)+0.1):floor(x_data(end)-0.1)];
y_interp = qp*nan; % this will hold our solution
kk=1; % indexes through the data
for cc=1:numel(qp)
% advance kk to where we can interpolate
% (this loop is guaranteed to not index out of bounds because x_data(end)>qp(end),
% but needs to be adjusted if this is not ensured prior to the loop)
while x_data(kk+1) < qp(cc)
kk = kk + 1;
end
% perform online interpolation
y_interp(cc) = myInterp(x_data(kk), x_data(kk+1), y_data(kk), y_data(kk+1), qp(cc));
end
As you can see, the logic is a lot simpler this way. The result is identical to y_interp_correct
. The inner while x_data...
loop serves the same purpose as your outer while
loop, and would be the place where you read your data from wherever it's coming from.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论