# 函数拟合
## 整体思路
将给定的坐标点分为 6 段部分,即左、左下、下、右、右上、上,6 部分。
其中左下和右上部分使用二次函数进行拟合,其他部分使用一次函数进行拟合。
## 观察数据
第 1-76 个点作为左边部分线性拟合
第 67-96 个点作为左下部分二次拟合
第 84-215 个点作为下部分线性拟合
第 216-275 个点作为右部分线性拟合
第 269-298 个点作为右上部分二次拟合
第 296-382 个点作为上部分一次拟合
## 代码实现
先得到 x、y 数据的散点向量,然后调用 polyfit 库函数,返回线性回归的函数参数,然后初始化较为密集的 x 横坐标作为样点横坐标,用求得的拟合函数代入样点横坐标得到样点纵坐标。此时较为密集的样点通过 plot 函数显示出来,即可得到拟合效果图
- 最终效果
![](https://www.writebug.com/myres/static/uploads/2022/7/27/29d861f78247bf36cf817e6830f6c547.writebug)
可以看出,在左下和右上通过二次函数拟合,在其他位置使用一次函数线性拟合
- 遇到的问题和解决方案
在最初选取拟合的坐标时,在 6 个曲线部分,每个部分选择的点集都不相交(相互互斥),此时的效果图并不理想:如下
![](https://www.writebug.com/myres/static/uploads/2022/7/27/ec8ce7e89a9ed4e98e8ac5ee2c2ce26e.writebug)
可以看出曲线中间有较大的空余,为了解决这个问题,不断地调整点集的区间(适当扩大),使每个区间的点集相互是有部分交集的,例如点 1-76 是第一部分,点 67-96 是第二部分,此时点 67-76 不但是左边部分的点来线性拟合,又是左下部分的点来二次拟合,效果会好很多,如下:
![](https://www.writebug.com/myres/static/uploads/2022/7/27/70fe73f872734c54d7711cce726191ad.writebug)
- 拟合结果:
左边(第 1-76 个点):y=0.0983x-381.095
左下(第 67-96 个点):y=0.0055
![](https://www.writebug.com/myres/static/uploads/2022/7/27/5ff2984ba3bdd7ddc00cab8c807d442c.writebug)
```c++
+4.5245x+299.2073
```
下边(第 84-215 个点):y=0.0208x-600.9287
右边(第 216-275 个点):y=-0.0721x+383.0611
右上(第 269-298 个点):y=-0.0056
![](https://www.writebug.com/myres/static/uploads/2022/7/27/99ab8c91e10fbaead03f1442cbc953d5.writebug)
```c++
+4.0934x-901.1372
```
上边(第 296-382 个点):y=0.011x-181.6471
函数插值
线性插值
整体思路
首先将标记为 1 的点单独储存在 v1 矩阵中,每一行为点的时间、横纵坐标,然后对于每一个标记为 0 的缺失点 Q,找到其最近的前后存在的点 AB,用 A 和 B 进行线性插值,该缺失点在线性插值直线 AB 上,且由 Q 的时间已知,AB 的到达时间也已知。不妨假设时间的比例(tQ-tA)/(tB-tA)和横坐标比例(xQ-xA)/(xB-xA)相等解出缺失点的横坐标,然后代入插值函数,求得缺失点坐标然后把缺失点存储在 v2 矩阵中,每一行为缺失点信息最后用 plot 把图像描绘出来
## 代码实现
利用 coord 的第二列为横坐标,第三列为纵坐标,第一列为时间将未缺失点存储在 v1 中,缺失点存储在 v2 中,利用假设物体在横坐标的投影匀速移动得到缺失时刻对应横坐标,然后利用插值函数(线性插值)获取纵坐标,利用 plot 函数描绘曲线。插值函数即获取斜率 k 和截距 b 即可
斜率 k=(y2-y1)/(x2-x1)
截距 b 为(x1*y2-x2*y1)/(x1-x2)
Temp_x,temp_y 用来暂时存储缺失点的横纵坐标,最终存储在 v2 矩阵中
最终效果
![](https://www.writebug.com/myres/static/uploads/2022/7/27/423c034c7d7920323b23a2e0759cf6ca.writebug)
## 三次样条插值
## 整体思路
- 对于 309 个未缺失的点,存在 308 个区间,每个区间都用三次函数插值
- 一共需要 4*308 个参数要确定
- 那么需要 4*408 个方程
- 其中 309 个是插值函数满足的点的插值条件个内点满足:函数值、导数值、二阶导数值连续
- 还需要 2 个边界条件,不妨设第一个点和最后一个点处导数是 0(自然边界起始条件)
- 核心思想就是解这 4*408 个方程得到 4*408 个系数的结果。
- 那么 M 为系数矩阵,Y 为方程的结果向量,
- 系数矩阵填上系数(对应于方程)
- 然后利用 M\Y 即可获得 X,即 4*408 个待定系数的值,然后描绘出这些插值函数。
- 同样假设物体在横坐标的投影匀速移动
- 那么缺失点横坐标可以用时间比例确定,再根据其所在区间,代入对应三次函数获得纵坐标的值
## 代码实现
同样将未缺失点存入 v1 矩阵,M 用来存系数矩阵,Y 用来存结果向量,X 为算出来的插值函数的结果系数的向量
- 最终效果
插值函数的效果图:
![](https://www.writebug.com/myres/static/uploads/2022/7/27/ffb7cabf345cde064c472530e391e832.writebug)
缺失点的插值效果图
![](https://www.writebug.com/myres/static/uploads/2022/7/27/038f600d30f28d9426654c68c85449d6.writebug)
红色为缺失点插值结果,蓝色点为未缺失点,黑色为插值曲线
## 多项式插值
## 实现思路
具体实现考虑使用分段二次函数插值,把 309 个存在点,308 个区间分成 154 组,每一个组有两个区间,三个点,相邻组之间会对存在的内点共用。
例如:x1、x2、x3 为第一组的三个插值点,x3、x4、x5 为第二组的插值点,相邻组对 x3 进行了共用。一共 154*3 个参数需要确定,每个二次函数确定 3 个参数。
可以列的方程也有 154*3 个,每个区间上都可以用待定系数的方式得到插值条件方程。
同理,填好 M 矩阵,和 Y 结果向量,运算得到二次函数系数结果向量 X
## 代码实现
用来存已知点
Vx1 和 vy1 存已知点横纵坐标
Vx2 和 vy2 存缺失点横纵坐标
缺失点横坐标用假设物体在横坐标的投影匀速移动来计算
缺失点纵坐标用插值函数进行计算
最终效果
![](https://www.writebug.com/myres/static/uploads/2022/7/27/dfc645ce2a0571b17cb54799621dee25.writebug)
插值方法对比
线性插值:优点是实现非常简单,只需要用原始点进行直线插值即可,缺点是在分段处衔接不够平滑,只能表示总体趋势,在细节上的增加难以有效表现
三次样条插值:优点是效果好,在分段处的函数值、斜率、凹凸性都非常平滑
缺点是方程数量比较庞大、复杂,一旦出现缺失点异常,最终结果会受到很大波动!
分段多项式插值(二次):优点是形式简单,且总体曲线比较平滑,应该说综合了线性插值和三次样条插值的有点,效果较好!
## 设计总结
在此项期末设计中,完成了基本功能:拟合、线性插值、三次样条插值
完成了两项拓展功能
即拟合时在特殊区间使用二次函数拟合
在插值时,实现了分段多项式插值,并进行了对比分析。
在整个设计的过程中
一则加深了对基础知识的理解和运用
二是体会到上机编程对数值分析这门课的意义
最后是初步了解了使用 matlab 的方法和其带来的便捷!
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请
点击举报。