You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Matlab三次样条插值:如何获取超数据最大值点并可视化

问题描述

已编写Matlab代码构建三次自然样条并绘制数据图,但不知道如何在图中显示原数据组外的点(例如f(2010))。希望在2000年后的有效区间(如t=2010)实现,但不知从何入手。

原代码

clear; clc;

t= [1850, 1875, 1900, 1925, 1950, 1975, 2000];
y= [285.2, 288.6, 295.7, 305.3, 311.3, 331.36, 369.64];

N= length(t); %number of points I want 
n=N-1 ; % number of subintervals

h=(t(N)-t(1))/n; %step size

A=[1,1,1,0],B=[2,0,0,0,2],C=[0,1,1,1];

Trid=diag(4*ones(1,n-1))+diag(A,-1)+diag(B)+diag(C,1);

for i=1:n-1
    f(i)= 6/h^2*(y(i+2)-2*y(i+1)+y(i));
end

f=f';
w=inv(Trid)*f;%since sigma 1 and sigma n+1 are both 0, we need to add 0 in the beginning and also in the end of then matrix
sigma=[0;w;0];%it is a nx1 matrix, be careful.

for i=1:n
    d(i)=y(i);
    b(i)=sigma(i)/2;
    a(i)=(sigma(i+1)-sigma(i))/(6*h);
    c(i)=(y(i+1)-y(i))/h-h/6*(2*sigma(i)+sigma(i+1));
end

r= 25; %subsubintervals for t ex. between 1850 and 1875, here i seperate it into 1 years per slot
hh=h/r; %step size of subsubintervals

x=t(1):hh:t(N);

for i=1:n
    for j=r*(i-1)+1:r*i
        s(j)=a(i)*(x(j)-t(i))^3+b(i)*(x(j)-t(i))^2+c(i)*(x(j)-t(i))+d(i);
    end
end

s(r*n+1)=y(N);

plot(t,y,'o')
hold on
plot(x,s,'-x')
hold off

解决方案

要计算并显示样条在原数据范围外的点,核心是利用最后一段样条的多项式表达式进行短距离外推(注意:样条外推可靠性有限,仅建议在靠近原区间的范围内使用)。具体实现如下:

1. 计算目标外推点的值

以t=2010为例,它属于最后一个子区间(1975-2000)的延伸范围,直接用最后一段的样条系数计算:

target_t = 2010;
% 最后一段的系数为a(n), b(n), c(n), d(n),对应区间t(n)到t(n+1)
target_s = a(n)*(target_t - t(n))^3 + b(n)*(target_t - t(n))^2 + c(n)*(target_t - t(n)) + d(n);

2. 扩展样条曲线的绘制范围

修改原代码中x的范围,让它覆盖到2010,同时用逻辑索引替代嵌套循环计算样条值(更简洁高效):

% 扩展x到2010
x = t(1):hh:2010;
s = zeros(size(x)); % 预分配内存提升性能

% 计算原区间内的样条值
for i=1:n
    idx = x >= t(i) & x <= t(i+1);
    s(idx) = a(i)*(x(idx)-t(i)).^3 + b(i)*(x(idx)-t(i)).^2 + c(i)*(x(idx)-t(i)) + d(i);
end

% 计算2000-2010外推区间的样条值
idx_extra = x > t(N);
s(idx_extra) = a(n)*(x(idx_extra)-t(n)).^3 + b(n)*(x(idx_extra)-t(n)).^2 + c(n)*(x(idx_extra)-t(n)) + d(n);

完整修改后的代码

clear; clc;

t= [1850, 1875, 1900, 1925, 1950, 1975, 2000];
y= [285.2, 288.6, 295.7, 305.3, 311.3, 331.36, 369.64];

N= length(t); 
n=N-1 ; 

h=(t(N)-t(1))/n; 

A=[1,1,1,0]; B=[2,0,0,0,2]; C=[0,1,1,1];

Trid=diag(4*ones(1,n-1))+diag(A,-1)+diag(B)+diag(C,1);

for i=1:n-1
    f(i)= 6/h^2*(y(i+2)-2*y(i+1)+y(i));
end

f=f';
w=inv(Trid)*f;
sigma=[0;w;0];

for i=1:n
    d(i)=y(i);
    b(i)=sigma(i)/2;
    a(i)=(sigma(i+1)-sigma(i))/(6*h);
    c(i)=(y(i+1)-y(i))/h-h/6*(2*sigma(i)+sigma(i+1));
end

r= 25; 
hh=h/r; 

% 扩展x到2010
x=t(1):hh:2010;
s = zeros(size(x)); % 预分配内存

% 计算原区间内的样条值
for i=1:n
    idx = x >= t(i) & x <= t(i+1);
    s(idx) = a(i)*(x(idx)-t(i)).^3 + b(i)*(x(idx)-t(i)).^2 + c(i)*(x(idx)-t(i)) + d(i);
end

% 计算外推区间的样条值
idx_extra = x > t(N);
s(idx_extra) = a(n)*(x(idx_extra)-t(n)).^3 + b(n)*(x(idx_extra)-t(n)).^2 + c(n)*(x(idx_extra)-t(n)) + d(n);

% 计算并标记2010的点
target_t = 2010;
target_s = a(n)*(target_t - t(n))^3 + b(n)*(target_t - t(n))^2 + c(n)*(target_t - t(n)) + d(n);

plot(t,y,'o','DisplayName','原始数据')
hold on
plot(x,s,'-x','DisplayName','样条曲线')
plot(target_t, target_s, 'rs','MarkerSize',10,'DisplayName','f(2010)')
legend
hold off
xlabel('年份')
ylabel('数值')
title('三次自然样条曲线及外推点')

关键说明

  • 样条外推是基于最后一段多项式的延伸,超出原数据区间越远,结果可靠性越低,仅适合短距离外推。
  • 用逻辑索引替代嵌套循环,代码更简洁,同时预分配s的内存可提升运行效率。
  • 新增图例、坐标轴标签和标题,让图表信息更清晰直观。

内容的提问来源于stack exchange,提问作者Teh Ais Kaw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 21:40:18