Skip to content

MATLAB - 线性插值

插值是估计已知数据点之间未知值的过程。当您有一组数据点 (x, v) 并想在新的查询点 xq 处找到值 vq 时,使用一维(1-D)插值。MATLAB 的主要函数是 interp1。

% 基本语法
vq = interp1(x, v, xq)
% 指定插值方法
vq = interp1(x, v, xq, method)
% 指定方法和外推行为
vq = interp1(x, v, xq, method, extrapolation)
% 使用默认采样点 [1, 2, 3, ...]
vq = interp1(v, xq, ...)
  • x:采样点位置的向量(自变量)。必须是单调的。
  • v:对应样本值(因变量)的向量或矩阵。如果 v 是矩阵,则对每列独立执行插值。
  • xq:您想要估计值的查询点向量或矩阵。
  • vq:输出,包含与 xq 对应的插值结果。

method 选项会显著改变结果。以下是最常见的选择:

MethodDescription & Best Use Case
'linear' (Default)使用直线连接点。快速简单。最适用于密集或近似线性数据。
'spline'三次样条插值。生成一条非常平滑的曲线,穿过所有数据点。适用于平滑、连续的信号。
'pchip'保形分段三次插值。防止过冲并保持单调性。非常适用于不应在点之间振荡的数据。
'makima'改进的 Akima 三次 Hermite 插值。类似于 'pchip',但通常在不产生过冲的情况下更准确地捕捉数据形状。是 'spline' 和 'pchip' 的推荐现代替代方案。
'nearest'“最近邻”插值。输出是最近采样点的值。适用于离散或分类数据。
%% --- 定义原始数据和查询数据 ---
x = 0:10; % 原始采样点
v = sin(x); % 原始值
xq = 0:0.25:10; % 查询点(更高分辨率)
%% --- 执行插值 ---
vq_linear = interp1(x, v, xq, 'linear');
vq_spline = interp1(x, v, xq, 'spline');
vq_makima = interp1(x, v, xq, 'makima');
%% --- 绘图比较 ---
figure;
hold on; % 允许在同一坐标轴上绘制多个图
% 绘制原始粗略数据
plot(x, v, 'o', 'MarkerSize', 10, 'DisplayName', '原始样本');
% 绘制插值结果
plot(xq, vq_linear, ':', 'LineWidth', 1.5, 'DisplayName', '线性');
plot(xq, vq_spline, '--', 'LineWidth', 1.5, 'DisplayName', '样条');
plot(xq, vq_makima, '-', 'LineWidth', 2, 'DisplayName', 'Makima');
hold off;
% --- 专业绘图的最后润色 ---
title('插值方法比较');
xlabel('X');
ylabel('sin(X)');
legend('show', 'Location', 'southwest');
grid on;

将生成一个图。它将显示原始 sin(x) 值,表示为大的蓝色圆圈。三条线将追踪这些点之间的路径:一条绿色虚线显示线性插值的直线连接;一条红色虚线显示样条插值的平滑、有时会过冲的曲线;一条粗蓝色实线显示来自 ‘makima’ 方法的平滑但无过冲的曲线。

如果 xq 中的查询点超出 x 的范围会发生什么?默认情况下,interp1 返回 NaN(非数值)。您可以使用 extrapolation 参数改变此行为。

x = 1:5;
v = [12, 16, 10, 18, 15];
xq = 0:0.5:6; % 查询点包含 [1, 5] 范围之外的值
% 执行线性插值并允许外推
vq_extrap = interp1(x, v, xq, 'linear', 'extrap');
% 执行插值并对范围外的点返回 0
vq_no_extrap = interp1(x, v, xq, 'linear', 0);
figure;
hold on;
plot(x, v, 'bo-', 'LineWidth', 2, 'MarkerSize', 8, 'DisplayName', 'Original Data');
plot(xq, vq_extrap, 'rx--', 'LineWidth', 1.5, 'DisplayName', 'With Extrapolation (''extrap'')');
plot(xq, vq_no_extrap, 'g*:', 'LineWidth', 1.5, 'DisplayName', 'With Extrapolation (value 0)');
hold off;
title('处理范围外查询点');
xlabel('x');
ylabel('值');
legend('show');
grid on;

该图将显示原始数据为实心蓝色圆圈。一条红色虚线将在原始数据范围的两端延伸,延续线性趋势。一条带有星号的绿色虚线将跟随数据范围内的插值,但在范围外的所有点处降至零。

interp1 针对向量和矩阵操作进行了高度优化。如果您有多个在相同 x 点采样的数据集,可以将它们放置在 v 的列中,并通过一次调用全部进行插值。这比使用循环快得多。

x = (0:4)'; % 在此示例中必须是列向量
% 三列中的三个数据集
v = [x.^2, x.^3, exp(x)];
xq = 0:0.1:4;
% 一次性插值所有三列
vq = interp1(x, v, xq, 'pchip');
% 绘图
figure;
plot(x, v, 'o', 'MarkerSize', 8);
hold on;
plot(xq, vq, '--', 'LineWidth', 1.5);
hold off;
title('插值多个数据集');
legend('原始数据集 1', '原始数据集 2', '原始数据集 3', 'Location', 'northwest');