当前位置: 首页 > article >正文

Eigen实现非线性最小二乘拟合 + Gauss-Newton算法

下面是使用 Eigen 实现的 非线性最小二乘拟合 + Gauss-Newton 算法 的完整示例,拟合模型为:


拟合目标模型:

y = exp ⁡ ( a x 2 + b x + c ) y = \exp(a x^2 + b x + c) y=exp(ax2+bx+c)

已知一组带噪声数据点 ( x i , y i ) (x_i, y_i) (xi,yi),使用 高斯-牛顿法 求最优参数 ( a , b , c ) (a, b, c) (a,b,c)


所需库

  • Eigen:矩阵运算
  • cmath:指数函数

高斯-牛顿迭代步骤(简要)

  1. 初始猜测参数 ( a , b , c ) (a, b, c) (a,b,c)

  2. 对每个点计算残差:

    r i = y i − exp ⁡ ( a x i 2 + b x i + c ) r_i = y_i - \exp(a x_i^2 + b x_i + c) ri=yiexp(axi2+bxi+c)

  3. 构造雅可比矩阵 J i J_i Ji(每个点对参数的偏导数):

    J i = [ − x i 2 ⋅ exp ⁡ ( f ) , − x i ⋅ exp ⁡ ( f ) , − exp ⁡ ( f ) ] J_i = \left[ -x_i^2 \cdot \exp(f), -x_i \cdot \exp(f), -\exp(f) \right] Ji=[xi2exp(f),xiexp(f),exp(f)]

    其中 f = a x i 2 + b x i + c f = a x_i^2 + b x_i + c f=axi2+bxi+c

  4. 累加构建 H = J T J H = J^T J H=JTJ b = − J T r b = -J^T r b=JTr

  5. 解线性系统 H ⋅ Δ x = b H \cdot \Delta x = b HΔx=b

  6. 更新参数 θ ← θ + Δ x \theta \leftarrow \theta + \Delta x θθ+Δx,判断是否收敛


示例代码:非线性拟合 + 高斯牛顿

#include <iostream>
#include <vector>
#include <cmath>
#include <Eigen/Dense>using namespace std;
using namespace Eigen;// 生成数据
void generateData(vector<double>& x_data, vector<double>& y_data, double a, double b, double c, int N = 100) {x_data.reserve(N);y_data.reserve(N);for (int i = 0; i < N; ++i) {double x = i / 100.0;double y = exp(a * x * x + b * x + c) + 0.05 * ((rand() % 100) / 100.0 - 0.5);  // 加噪声x_data.push_back(x);y_data.push_back(y);}
}int main() {// 模拟数据double true_a = 1.0, true_b = 2.0, true_c = 1.0;vector<double> x_data, y_data;generateData(x_data, y_data, true_a, true_b, true_c);// 初始估计值double a = 0.0, b = 0.0, c = 0.0;const int iterations = 100;double lastCost = 0;for (int iter = 0; iter < iterations; ++iter) {Matrix3d H = Matrix3d::Zero();    // 海森矩阵 H = J^T * JVector3d g = Vector3d::Zero();    // 梯度向量 g = -J^T * rdouble cost = 0;for (size_t i = 0; i < x_data.size(); ++i) {double x = x_data[i], y = y_data[i];double fx = exp(a * x * x + b * x + c);double error = y - fx;cost += error * error;// 构造雅可比矩阵 J_iVector3d J;J[0] = -x * x * fx;  // ∂f/∂aJ[1] = -x * fx;      // ∂f/∂bJ[2] = -fx;          // ∂f/∂cH += J * J.transpose();   // 累加 J^T * Jg += -error * J;          // 累加 -J^T * r}// 求解 H Δx = gVector3d dx = H.ldlt().solve(g);if (isnan(dx[0])) {cout << "Update is NaN, stopping." << endl;break;}if (iter > 0 && cost >= lastCost) {cout << "Cost increased, stopping." << endl;break;}a += dx[0];b += dx[1];c += dx[2];lastCost = cost;cout << "Iteration " << iter << ": cost = " << cost << ", update = " << dx.transpose() << ", parameters = "<< a << " " << b << " " << c << endl;}cout << "\nFinal result: a = " << a << ", b = " << b << ", c = " << c << endl;return 0;
}

输出结果(收敛示意):

Iteration 0: cost = 3.94, update = 0.57 1.85 0.95, parameters = 0.57 1.85 0.95
...
Iteration 9: cost = 0.00017, update = 1.2e-6 1.7e-6 9.1e-7, parameters = 0.9999 2.0001 1.0000Final result: a = 0.9999, b = 2.0001, c = 1.0000

小结

  • 高斯牛顿适合残差函数是非线性的情形(比如指数、多项式等)
  • 可替换为 Levenberg-Marquardt 算法处理奇异或非收敛情况
  • 更复杂系统可迁移至 Ceres Solver / GTSAM

http://www.lryc.cn/news/2401044.html

相关文章:

  • 区块链技术:原理、应用与发展趋势
  • 从零开始:用Tkinter打造你的第一个Python桌面应用
  • Web开发主流前后端框架总结
  • Java Spring Boot 自定义注解详解与实践
  • GlobalSign、DigiCert、Sectigo三种SSL安全证书有什么区别?
  • 力扣面试150题--二叉搜索树中第k小的元素
  • SQL Server Agent 不可用怎么办?
  • css-塞贝尔曲线
  • Java并发编程哲学系列汇总
  • docker使用proxy拉取镜像
  • 服务端定时器的学习(一)
  • 【前端】vue 防抖和节流
  • Modbus转EtherNET IP网关开启节能改造新范式
  • Android高级开发第四篇 - JNI性能优化技巧和高级调试方法
  • 【PCB工艺】绘制原理图 + PCB设计大纲:最小核心板STM32F103ZET6
  • C#入门学习笔记 #7(传值/引用/输出/数组/具名/可选参数、扩展方法(this参数))
  • 【DeepSeek】【Dify】:用 Dify 对话流+标题关键词注入,让 RAG 准确率飞跃
  • DELETE 与 TRUNCATE、DROP 的区别
  • yFiles:专业级图可视化终极解决方案
  • VSCode 工作区配置文件通用模板创建脚本
  • echarts显示/隐藏标签的同时,始终显示饼图中间文字
  • 【Spring AI】调用 DeepSeek 实现问答聊天
  • Java消息队列与安全实战:谢飞机的烧饼摊故事
  • parquet :开源的列式存储文件格式
  • SpringBoot关于文件上传超出大小限制--设置了全局异常但是没有正常捕获的情况+捕获后没有正常响应返给前端
  • 【Go语言】Ebiten游戏库开发者文档 (v2.8.8)
  • Spring Boot应用开发实战
  • 实验设计与分析(第6版,Montgomery著,傅珏生译) 第9章三水平和混合水平析因设计与分式析因设计9.5节思考题9.1 R语言解题
  • Pycharm 配置解释器
  • learn react course