找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 3434|回复: 2

【Julia1.5.2】三次样条插值

[复制链接]
发表于 2020-12-1 17:44:33 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
本帖最后由 流星雨 于 2020-12-1 18:29 编辑

参考数目:
【1】《数值分析》(李乃成、梅立泉编著,科学出版社,ISBN:978-7-03-032192-3)

背景:
当得到n个x和对应的点y时,如果需要得到一条插值曲线,并且曲线在每个点上二阶导数连续——曲线光滑,早期的做法是用压铁将一根富有弹性的细条(样条,Spline)固定在这些点上,然后沿着细条画出一根光滑的曲线【1】。

结构:
采用Julia语言(1.5.2)编制脚本Spline.jl,主要功能为求解三类边界条件(双侧二阶导数已知、双侧一阶导数已知、双侧周期)约束下的三次样条插值曲线。
脚本包含5个函数:cal_k(计算多项式(x±x_i )^n的系数)、seletbound(选择边界条件)、cal_M(计算每个点的二阶导数M)、Spline_out(插值函数输出部分)、cal_hμλd(计算hμλd,不包含首尾项)。另为方便调试,未封装“数据读入部分(读取表格数据)”和“计算设置部分(设置插值点并获取插值函数值)”。
QQ图片20201201173805.png

算法原理:
1.png 2.png 3.png 4.png

使用说明:
安装Julia编译环境JuliaPro-1.5.2-1,可在URL:https://juliacomputing.com/products/juliapro/下载最新版的JuliaPro-1.5.3-1。安装完毕后用Juliapro打开文件Spline.jl。在REPL窗口中输入pwd()查看当前工作路径,可以选择在当前工作路径下放置输入文件xy.csv和boundary.csv,分别为xy点集和边界条件。也可在脚本文件Spline.jl中更改:
ID = "C:\\Users\\hp\\xy.csv"
ID_b = "C:\\Users\\hp\\boundary.csv"
其中C:\\Users\\hp为工作路径。在工作路径下放置xy.csv和boundary.csv,格式见附件。特别地,当选定“周期”边界条件时,应确保所给的数据满足式(3-2),此时在“周期”列随便填入一个内容(不能是none,建议填1),其余列填none。
单击▶即可运行。UI右侧Workspace窗口可实时显示各变量值。
计算设置部分(153行后)采用两种插值方式:单值和等距取点。其中变量xt表示单值插值点,单击▶计算后右侧窗口St为对应的插值函数值。number表示在插值区间内取等距点的数量,单击▶计算后右侧窗口Stest为对应的插值函数值集合。
运行结束后会在工作目录下生成插值函数表out.csv,第一列为插值点,第二列为对应的插值函数值。

附上参考书【1】给出的使用建议:
三次样条插值具有良好的收敛性、计算稳定性和二阶光滑性,当线性插值不可满足精度时可优先考虑;
慎用高次插值,避免龙格现象。
三次样条插值.rar (128.51 KB, 下载次数: 0)
5.png
回复

使用道具 举报

发表于 2020-12-11 01:57:15 | 显示全部楼层
我表示这些数学公式我看不下去,但样条线我还是懂的
回复 赞! 靠!

使用道具 举报

发表于 2020-12-28 09:07:35 | 显示全部楼层
我来个python的!
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Sun Dec 27 19:30:57 2020
  4. Copyright@Xi'an Jiaotong University - NuTHeL
  5. @author: Zhou Xingguang
  6. """

  7. import numpy as np
  8. import matplotlib.pyplot as plt

  9. class CubicSpline(object):
  10.     def __init__(self, x, y):
  11.         self.x = x[:]
  12.         self.y = y[:]
  13.    
  14.     @staticmethod
  15.     def SecondOrderDiff(x, y):
  16.         return np.array([((y[i+2]-y[i+1])/(x[i+2]-x[i+1])-(y[i+1]-y[i])/(x[i+1]-x[i]))/(x[i+2]-x[i]) for i in range(len(x)-2)])
  17.    
  18.     def Interpolation(self):
  19.         h = np.array([self.x[i+1]-self.x[i] for i in range(len(self.x)-1)])
  20.         u = np.array([h[i] / (h[i]+h[i+1]) for i in range(len(h)-1)])
  21.         my_lambda = 1 - u
  22.         d = 6 * CubicSpline.SecondOrderDiff(self.x, self.y)
  23.         # generate the M matrix
  24.         Matrix = 2*np.identity(np.size(d), dtype=float)
  25.         Matrix[0, 1] = my_lambda[0]
  26.         Matrix[np.size(d)-1, np.size(d)-2] = u[np.size(d)-1]
  27.         for i in range(1, np.size(d)-1):
  28.             Matrix[i, i-1] = u[i]
  29.             Matrix[i, i+1] = my_lambda[i]
  30.         # solve the function group
  31.         M = np.linspace(0, 1, len(self.x))
  32.         M[0] = 0
  33.         M[1:len(self.x)-1] = np.linalg.solve(Matrix, d)
  34.         M[len(self.x)-1] = 0
  35.         return M, h
  36.    
  37.     def GenerateFunc(self, x):
  38.         M, h = self.Interpolation()
  39.         # generate the coefficient matrix
  40.         coeff = np.zeros((np.size(self.x)-1, 4), dtype=float)
  41.         for i in range(0, np.size(self.x)-1):
  42.             coeff[i][0] = M[i] / (6*h[i])
  43.             coeff[i][1] = M[i+1] / (6*h[i])
  44.             coeff[i][2] = (self.y[i] - h[i]**2*M[i]/6)/h[i]
  45.             coeff[i][3] = (self.y[i+1] - h[i]**2*M[i+1]/6)/h[i]
  46.         
  47.         # get the x in which section
  48.         location = 0
  49.         for i in range(len(self.x)-1):
  50.             if self.x[i] <= x <= self.x[i+1]:
  51.                 break
  52.             location += 1
  53.         
  54.         result = (self.x[location+1]-x)**3*coeff[location][0]
  55.         result += (x-self.x[location])**3*coeff[location][1]
  56.         result += (self.x[location+1]-x)*coeff[location][2]
  57.         result += (x-self.x[location]) * coeff[location][3]
  58.         return result


  59. if __name__ == '__main__':
  60.     x = np.linspace(-1, 1, 11)
  61.     y = 1/(1+25*x**2)
  62.     C = CubicSpline(x, y)
  63.     for i in range(10):
  64.         test_x = np.linspace(x[i], x[i+1], 5)
  65.         test_y = []
  66.         for j in range(0, 5):
  67.             test_y.append(C.GenerateFunc(test_x[j]))
  68.         plt.scatter(test_x[0], test_y[0])
  69.         plt.scatter(test_x[1:5], test_y[1:5], marker='x')
  70.    
  71.     # draw the analytic solution
  72.     plt.plot(test_x, test_y)
  73.    
  74.     Graphic_x = np.linspace(-1, 1, 100)
  75.     Graphic_y = 1/(1+25*Graphic_x**2)
  76.     plt.plot(Graphic_x, Graphic_y)
  77.     plt.show()
复制代码

插值结果如下所示,其中橘色的实线为解析解y=1/(25*x^2)的图像,圆点和打x的点为插值结果,每两个圆点代表了插值的分段区间。
Figure 2020-12-28 090709.png
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-12-21 23:34 , Processed in 0.035425 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表