C#实现分段三次Hermite插值

目录

一、Hermite插值介绍

1、功能说明

2、数学方法

二、代码实现

1、CubicHermiteInterpolator类封装

2、应用示例

三、导数值的获取方式 

1、数学方法介绍

2、代码应用示例

四、其它封装的分段三次Hermite插值类

1、方式一

(1)封装代码

(2)应用示例

2、方法二

(1)封装代码

(2)应用示例

五、曲线图像

1、分段三次Hermite插值

2、三次样条曲线

六、下载连接


一、Hermite插值介绍

1、功能说明

功能:实现 三次埃尔米特插值(Cubic Hermite Interpolation),用于在两个已知点之间构造一条平滑曲线,保证插值函数在端点处匹配原函数的值 和一阶导数。

核心方法 :根据输入的坐标点和导数,计算插值结果。

2、数学方法

教材《数值分析》-第五版   作者:李庆扬

二、代码实现

1、CubicHermiteInterpolator类封装

    public class CubicHermiteInterpolator{/// <summary>/// x数值数组/// </summary>private readonly double[] _x;/// <summary>/// y轴数值数组/// </summary>private readonly double[] _y;/// <summary>/// y'导数值数组/// </summary>private readonly double[] _yPrime;/// <summary>/// 构造函数/// </summary>/// <param name="x">x数值数组</param>/// <param name="y">y数值数组</param>/// <param name="yPrime">y'导数值数组</param>public CubicHermiteInterpolator(double[] x, double[] y, double[] yPrime){ValidateInput(x, y, yPrime);_x = (double[])x.Clone();_y = (double[])y.Clone();_yPrime = (double[])yPrime.Clone();}/// <summary>/// 数据检验/// </summary>/// <param name="x">x数值数组</param>/// <param name="y">y数值数组</param>/// <param name="yPrime">y'导数值数组</param>private void ValidateInput(double[] x, double[] y, double[] yPrime){if (x == null || y == null || yPrime == null)throw new ArgumentNullException("Input arrays cannot be null.");if (x.Length != y.Length || x.Length != yPrime.Length)throw new ArgumentException("All input arrays must have the same length.");if (x.Length < 2)throw new ArgumentException("At least two points are required for interpolation.");for (int i = 0; i < x.Length - 1; i++){if (x[i] >= x[i + 1])throw new ArgumentException("x must be strictly increasing.");}}/// <summary>/// 经过插值计算后,x值对应输出y值/// </summary>/// <param name="x">输入x值</param>/// <returns>输出插值后的y值</returns>public double Evaluate(double x){int segmentIndex = FindSegmentIndex(x);double x0 = _x[segmentIndex];double x1 = _x[segmentIndex + 1];double y0 = _y[segmentIndex];double y1 = _y[segmentIndex + 1];double y0Prime = _yPrime[segmentIndex];double y1Prime = _yPrime[segmentIndex + 1];double h = x1 - x0;double t = (x - x0) / h;// Calculate basis functionsdouble t2 = t * t;double t3 = t2 * t;double h00 = 2 * t3 - 3 * t2 + 1;double h10 = -2 * t3 + 3 * t2;double h01 = t3 - 2 * t2 + t;double h11 = t3 - t2;// Compute interpolated valuereturn y0 * h00 + y1 * h10 + y0Prime * h01 * h + y1Prime * h11 * h;}/// <summary>/// 检查输入的x值,有没有超出数组范围/// </summary>/// <param name="x"></param>/// <returns></returns>private int FindSegmentIndex(double x){if (x < _x[0] || x > _x[_x.Length - 1])throw new ArgumentOutOfRangeException("x", "x is outside the interpolation range.");int low = 0;int high = _x.Length - 1;int segmentIndex = 0;while (low <= high){int mid = (low + high) / 2;if (_x[mid] <= x){segmentIndex = mid;low = mid + 1;}else{high = mid - 1;}}// Handle case where x is exactly the last pointif (segmentIndex == _x.Length - 1)segmentIndex--;return segmentIndex;}}

2、应用示例

        private void button1_Click(object sender, EventArgs e){// 示例数据double[] x = { 0, 1, 2, 3 };double[] y = { 0, 1, 0, -1 };double[] yPrime = { 1, 0, -1, 0 };var interpolator = new CubicHermiteInterpolator(x, y, yPrime);// 测试插值double y0 = interpolator.Evaluate(0.0);     //输出0.0double y1 = interpolator.Evaluate(0.5);     //输出0.625double y2 = interpolator.Evaluate(1.0);     //输出1.0double y3 = interpolator.Evaluate(1.5);     //输出0.625double y4 = interpolator.Evaluate(2.0);     //输出0.0double y5 = interpolator.Evaluate(2.5);     //输出-0.625double y6 = interpolator.Evaluate(3.0);     //输出-1}

三、导数值的获取方式 

1、数学方法介绍

代码

// 计算 yPrime[1](x=1 处的导数)
double h = x[2] - x[1]; // h = 1
yPrime[1] = (y[2] - y[0]) / (2 * h); // (0 - 0)/(2*1) = 0// 计算 yPrime[2](x=2 处的导数)
yPrime[2] = (y[3] - y[1]) / (2 * h); // (-1 - 1)/(2*1) = -1// 边界点 x=0 用向前差分
yPrime[0] = (y[1] - y[0]) / h; // (1 - 0)/1 = 1// 边界点 x=3 用向后差分
yPrime[3] = (y[3] - y[2]) / h; // (-1 - 0)/1 = -1

这种设定可以生成一个平滑的插值曲线

2、代码应用示例

代码

        private void button2_Click(object sender, EventArgs e){double[] x = { 0, 1, 2, 3 };double[] y = { 0, 1, 0, -1 };double[] yPrime = new double[4];// 计算 yPrime[1](x=1 处的导数)double h = x[2] - x[1]; // h = 1yPrime[1] = (y[2] - y[0]) / (2 * h); // (0 - 0)/(2*1) = 0// 计算 yPrime[2](x=2 处的导数)yPrime[2] = (y[3] - y[1]) / (2 * h); // (-1 - 1)/(2*1) = -1// 边界点 x=0 用向前差分yPrime[0] = (y[1] - y[0]) / h; // (1 - 0)/1 = 1// 边界点 x=3 用向后差分yPrime[3] = (y[3] - y[2]) / h; // (-1 - 0)/1 = -1var interpolator = new CubicHermiteInterpolator(x, y, yPrime);// 测试插值double y0 = interpolator.Evaluate(0.0);     //输出0.0double y1 = interpolator.Evaluate(0.5);     //输出0.625double y2 = interpolator.Evaluate(1.0);     //输出1.0double y3 = interpolator.Evaluate(1.5);     //输出0.625double y4 = interpolator.Evaluate(2.0);     //输出0.0double y5 = interpolator.Evaluate(2.5);     //输出-0.5double y6 = interpolator.Evaluate(3.0);     //输出-1}

四、其它封装的分段三次Hermite插值类

1、方式一

(1)封装代码

     public class CubicHermiteInterpolator{private double[] xPoints;           // 已知的x点private double[] yPoints;           // 对应的y点(函数值)private double[] yDerivatives;      // 对应的y'点(导数值)public CubicHermiteInterpolator(double[] xPoints, double[] yPoints, double[] yDerivatives){if (xPoints.Length != yPoints.Length || xPoints.Length != yDerivatives.Length)throw new ArgumentException("xPoints, yPoints, and yDerivatives must have the same length.");this.xPoints = xPoints;this.yPoints = yPoints;this.yDerivatives = yDerivatives;}public double Interpolate(double x){int n = xPoints.Length;if (n == 0) throw new InvalidOperationException("No data points available.");if (x <= xPoints[0]) return yPoints[0]; // 边界情况处理if (x >= xPoints[n - 1]) return yPoints[n - 1]; // 边界情况处理int i = 0;while (x > xPoints[i + 1]) i++; // 找到正确的区间索引idouble h = xPoints[i + 1] - xPoints[i];double t = (x - xPoints[i]) / h;double t2 = t * t;double t3 = t2 * t;double a = 2 * t3 - 3 * t2 + 1; // a(t) = 2t^3 - 3t^2 + 1double b = -2 * t3 + 3 * t2; // b(t) = -2t^3 + 3t^2double c = t3 - 2 * t2 + t; // c(t) = t^3 - 2t^2 + tdouble d = t3 - t2; // d(t) = t^3 - t^2return a * yPoints[i] + b * yPoints[i + 1] + (c * h * yDerivatives[i] + d * h * yDerivatives[i + 1]);}}

(2)应用示例

private void Form1_Load(object sender, EventArgs e){double[] xPoints = { 0, 1, 2, 3 };                                      // x坐标点double[] yPoints = { 0, 1, 4, 9 };                                      // y坐标点(函数值)double[] yDerivatives = { 1, 0, -3, 0 };                                // 导数值(例如,在x=1处导数为0,在x=2处导数为-3)var interpolator = new CubicHermiteInterpolator(xPoints, yPoints, yDerivatives);double result = interpolator.Interpolate(1.5);                          // 在x=1.5处计算插值结果Console.WriteLine("Interpolated value at x=1.5: " + result);            // 应该输出接近2.875的值,因为这是从y=4到y=9的过渡点附近的值。}

2、方法二

(1)封装代码

// 定义数据点结构public struct HermitePoint{public double X { get; set; }public double Y { get; set; }public double M { get; set; } // 导数值}public class CubicHermiteInterpolator{private List<HermitePoint> points;public CubicHermiteInterpolator(IEnumerable<HermitePoint> dataPoints){points = dataPoints.OrderBy(p => p.X).ToList();}// 核心插值方法public double Interpolate(double x){// 1. 边界检查if (points.Count < 2) throw new ArgumentException("至少需要两个点");if (x <= points[0].X) return points[0].Y;if (x >= points.Last().X) return points.Last().Y;// 2. 查找所在区间int index = FindSegmentIndex(x);HermitePoint p0 = points[index];HermitePoint p1 = points[index + 1];// 3. 计算归一化参数tdouble deltaX = p1.X - p0.X;double t = (x - p0.X) / deltaX;// 4. 计算Hermite基函数double t2 = t * t;double t3 = t2 * t;double h00 = 2 * t3 - 3 * t2 + 1;double h10 = t3 - 2 * t2 + t;double h01 = -2 * t3 + 3 * t2;double h11 = t3 - t2;// 5. 组合计算结果(注意导数项需要乘以deltaX)return h00 * p0.Y +h10 * deltaX * p0.M +h01 * p1.Y +h11 * deltaX * p1.M;}// 二分查找所在区间private int FindSegmentIndex(double x){int low = 0;int high = points.Count - 2;while (low <= high){int mid = (low + high) / 2;if (points[mid].X <= x && x < points[mid + 1].X)return mid;if (x < points[mid].X)high = mid - 1;elselow = mid + 1;}return points.Count - 2;}}

(2)应用示例

        private void Form1_Load(object sender, EventArgs e){// 创建插值点(包含导数值)//var points = new List<HermitePoint>//{//    new HermitePoint { X = 0, Y = 0, M = 1 },   // 导数为1//    new HermitePoint { X = 2, Y = 4, M = 0 },   // 导数为0//    new HermitePoint { X = 5, Y = 1, M = -1 }   // 数为为-1 //};var points = new List<HermitePoint>{new HermitePoint { X = 0, Y = 0, M = 1 },   //new HermitePoint { X = 1, Y = 1, M = 0 },   //new HermitePoint { X = 2, Y = 4, M = -3 },   //new HermitePoint { X = 3, Y = 9, M = 0 }};var interpolator = new CubicHermiteInterpolator(points);// 在x=1.5处插值double result = interpolator.Interpolate(1.5);      //输出2.875// 在x=3处插值result = interpolator.Interpolate(3);               //输出9.0}

五、曲线图像

1、分段三次Hermite插值

2、三次样条曲线

六、下载连接

https://download.csdn.net/download/panjinliang066333/90493389

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/73067.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

重要重要!!fisher矩阵元素有什么含义和原理; Fisher 信息矩阵的形式; 得到fisher矩阵之后怎么使用

fisher矩阵元素有什么含义和原理 目录 fisher矩阵元素有什么含义和原理一、对角线元素( F i , i F_{i,i} Fi,i​)的含义与原理二、非对角线元素( F i , j F_{i,j} Fi,j​)的含义与原理Fisher 信息矩阵的形式矩阵的宽度有位置权重数量决定1. **模型参数结构决定矩阵维度**2.…

【STM32】uwTick在程序中的作用及用法,并与Delay函数的区别

一、uwTick 的作用 1.系统时间基准 uwTick 是一个全局变量&#xff08;volatile uint32_t&#xff09;&#xff0c;记录系统启动后的毫秒级时间累计值。默认情况下&#xff0c;它由 SysTick 定时器每 ​1ms 自动递增一次&#xff08;通过 HAL_IncTick() 函数。例如&#xff0…

docker速通

docker 镜像操作搜索镜像拉取镜像查看镜像删除镜像 容器操作!查看容器运行容器run命令详细介绍 启动容器停止容器重启容器查看容器状态查看容器日志删除容器进入容器 保存镜像提交保存加载 分享社区登录命名推送 docker存储目录挂载卷映射查看所有容器卷创建容器卷查看容器卷详…

OpenCV旋转估计(5)图像拼接的一个函数waveCorrect()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 waveCorrect 是OpenCV中用于图像拼接的一个函数&#xff0c;特别适用于全景图拼接过程中校正波浪形失真&#xff08;Wave Correction&#xff09…

Python、MATLAB和PPT完成数学建模竞赛中的地图绘制

参加数学建模比赛时&#xff0c;很多题目——诸如统计类、数据挖掘类、环保类、建议类的题目总会涉及到地理相关的情景&#xff0c;往往要求我们制作与地图相关的可视化内容。如下图&#xff0c;这是21年亚太赛的那道塞罕坝的题目&#xff0c;期间涉及到温度、降水和森林覆盖率…

深入了解 C# 中的 LINQ:功能、语法与应用解析

1. 什么是 LINQ&#xff1f; LINQ&#xff08;Language Integrated Query&#xff0c;语言集成查询&#xff09;是 C# 和其他 .NET 语言中的一种强大的查询功能&#xff0c;它允许开发者在语言中直接执行查询操作。LINQ 使得开发者可以使用 C# 语法&#xff08;或 VB.NET&…

DeepSeek R1 本地部署指南 (3) - 更换本地部署模型 Windows/macOS 通用

0.准备 完成 Windows 或 macOS 安装&#xff1a; DeepSeek R1 本地部署指南 (1) - Windows 本地部署-CSDN博客 DeepSeek R1 本地部署指南 (2) - macOS 本地部署-CSDN博客 以下内容 Windows 和 macOS 命令执行相同&#xff1a; Windows 管理员启动&#xff1a;命令提示符 CMD ma…

【总结】Pytest vs Behave,BDD 测试框架哪家强?

引言 在测试驱动开发(TDD)和行为驱动开发(BDD)流行的今天&#xff0c;Pytest和 Behave 成为了 Python 生态中最常见的自动化测试框架。那么&#xff0c;究竟该选择哪一个&#xff1f;它们各自有哪些优缺点&#xff1f;本篇文章将为你全面解析&#xff01; 1. 什么是 Pytest&a…

k8s中service概述(二)NodePort

NodePort 是 Kubernetes 中一种用于对外暴露服务的 Service 类型。它通过在集群的每个节点上开放一个静态端口&#xff08;NodePort&#xff09;&#xff0c;使得外部用户可以通过节点的 IP 地址和该端口访问集群内部的服务。以下是关于 NodePort Service 的详细说明&#xff1…

HTML5 Video标签详细教程

HTML5 Video标签详细教程 简介 HTML5引入的<video>标签为网页提供了原生视频播放功能&#xff0c;无需依赖Flash等第三方插件。它使得在网页中嵌入和控制视频内容变得简单而强大。本教程将详细介绍<video>标签的使用方法、属性、事件以及相关技术。 基本用法 最…

Linux系统崩溃破案实录

现代计算环境中&#xff0c;系统的稳定性和可靠性至关重要。然而&#xff0c;即使是最优化的系统也可能会由于硬件故障、软件漏洞或配置错误而崩溃。为了解决这一问题&#xff0c;Linux系统提供了强大的内核崩溃转储机制&#xff0c;本文介绍如何收集和分析崩溃日志&#xff0c…

tcping 命令的使用,ping IP 和端口

1. ‌Windows系统安装‌ ‌下载tcping工具‌&#xff1a;根据系统位数&#xff08;32位或64位&#xff09;下载对应的tcping.exe文件。‌安装步骤‌&#xff1a; 将下载的tcping.exe文件复制到C:\Windows\System32目录下。如果下载的是64位版本&#xff0c;需将文件名改为tcpi…

深度学习框架PyTorch——从入门到精通(6.1)自动微分

使用torch.autograd自动微分 张量、函数和计算图计算梯度禁用梯度追踪关于计算图的更多信息张量梯度和雅可比乘积 在训练神经网络时&#xff0c;最常用的算法是反向传播。在该算法中&#xff0c;参数&#xff08;模型权重&#xff09;根据损失函数的梯度相对于给定参数进行调整…

跟我学C++中级篇——std::not_fn

一、std::not_fn定义和说明 std::not_fn这个模板函数非常有意思&#xff0c;在前面我们学习过wrapper&#xff08;包装器&#xff09;&#xff0c;其实它就是通过封装一个包装器来实现返回值的非。它的基本定义如下&#xff1a; template< class F > /* 未指定 */ not_…

阶跃星辰开源300亿参数视频模型Step-Video-TI2V:运动可控+102帧长视频生成

阶跃星辰&#xff08;StepFun&#xff09;正式开源其新一代图生视频模型 Step-Video-TI2V &#xff0c;该模型基于300亿参数的Step-Video-T2V训练&#xff0c;支持文本与图像联合驱动生成长达102帧的高质量视频&#xff0c;在运动控制与场景适配性上实现突破。 核心亮点 …

java查询es超过10000条数据

java查询es超过10000条数据 背景:需要每天零点导出es中日志数据到数据库中给数据分析人员做清洗&#xff0c;然后展示给业务人员。但在es中默认一次最多只能查询10000条数据。 在这里我就只贴一下关键代码 SearchRequest searchRequest new SearchRequest("索引名"…

使用 libevent 构建高性能网络应用

使用 libevent 构建高性能网络应用 在现代网络编程中&#xff0c;高性能和可扩展性是开发者追求的核心目标。为了实现这一目标&#xff0c;许多开发者选择使用事件驱动库来管理 I/O 操作和事件处理。libevent 是一个轻量级、高性能的事件通知库&#xff0c;广泛应用于网络服务…

HeyGem.ai 全离线数字人生成引擎加入 GitCode:开启本地化 AIGC 创作新时代

在人工智能技术飞速演进的时代&#xff0c;数据隐私与创作自由正成为全球开发者关注的焦点。硅基智能旗下开源项目 HeyGem.ai 近日正式加入 GitCode&#xff0c;以全球首个全离线数字人生成引擎的颠覆性技术&#xff0c;重新定义人工智能生成内容&#xff08;AIGC&#xff09;的…

【leetcode hot 100 39】组合总和

错误解法一&#xff1a;每一次回溯都遍历提供的数组 class Solution {public List<List<Integer>> combinationSum(int[] candidates, int target) {List<List<Integer>> result new ArrayList<List<Integer>>();List<Integer> te…

VSCODE右下角切换环境没用

VSCODE惦记右下角python版本&#xff0c;切换别的虚拟环境时&#xff0c;始终切换不了&#xff0c;同时右下角弹出&#xff1a; Client Pylance: connection to server is erroring. 取消继承环境也改了。https://www.cnblogs.com/coreylin/p/17509610.html 还是不行&#xf…