【TOOL】ceres学习笔记(二) —— 自定义函数练习

文章目录

  • 一、曲线方程
    • 1. 问题描述
    • 2. 实现方案

一、曲线方程

1. 问题描述

现有数学模型为 f ( x ) = A e x + B s i n ( x ) + C x D f(x)=Ae^x+Bsin(x)+Cx^D f(x)=Aex+Bsin(x)+CxD ,但不知道 A A A B B B C C C D D D 各参数系数,实验数据中含有噪声即 f ( x ) = A e x + B s i n ( x ) + C x D + n o i s e f(x)=Ae^x+Bsin(x)+Cx^D+noise f(x)=Aex+Bsin(x)+CxD+noise ,此时用ceres进行拟合。

2. 实现方案

2.1 含噪声的数据生成
A = 0.02 A=0.02 A=0.02 B = 3.2 B=3.2 B=3.2 C = 1.1 C=1.1 C=1.1 D = 3 D=3 D=3 为例进行实验数据生成。

// 生成曲线对应真值数据
double function(double x){return 0.02*exp(x)+3.2*sin(x)+1.1*pow(x,3);
}// 真值数据添加噪声std::vector<std::pair<double, double>> measurement_data_generation(double begin,double end,double stride,double (*fun)(double)){std::vector<std::pair<double,double>> out;//创建一个 std::mt19937 类型的随机数生成器 mt,并使用当前时间的微秒数作为种子,以确保每次运行时生成的随机数序列不同std::mt19937 mt;mt.seed(std::chrono::system_clock::now().time_since_epoch().count());for(double i=begin;i<end;i=i+stride){// 使用 std::uniform_real_distribution<double>(0, 20) 生成一个在 0 到 20 之间的随机 double 值double y_=std::uniform_real_distribution<double>(0,20)(mt);// 将随机值 y_ 与通过调用 fun(i) 得到的值相加y_=y_+fun(i);out.push_back(std::make_pair(i,y_));}return out;
}

2.2 自定义残差计算模型
根据数学模型搭建ceres残差计算模型:

struct my_ceres_test{
public:my_ceres_test(double x,double y):x_(x),y_(y){}template<typename T>bool operator()(const T* const A, const T* const B, const T* const C,const T* const D, T* residual)const{residual[0]=y_-A[0]*exp(x_)-B[0]*sin(x_)-C[0]*pow(x_,D[0]);return true;}private:double x_;double y_;
};

2.3 完整代码
完整程序如下:

#include <ceres/ceres.h>
#include <iostream>
#include "glog/logging.h"
#include <random>
#include <chrono>
#include <cmath>// #define MATPLOT#ifdef MATPLOT
#include "matplotlibcpp.h"
#endif// 生成曲线对应真值数据
double function(double x){return 0.02*exp(x)+3.2*sin(x)+1.1*pow(x,3);
}/*** @description: 真值数据添加噪声* @date: 2024/06/23* @param[i]: begin:数据生成的起始值 * @param[i]: end:数据生成的结束值(不包含在内)* @param[i]: stride:每次迭代的步长* @param[i]: fun:一个函数指针,指向一个接受一个 double 类型参数并返回一个 double 类型值的函数* @return: std::vector<std::pair<double, double>>
**/std::vector<std::pair<double, double>> measurement_data_generation(double begin,double end,double stride,double (*fun)(double)){std::vector<std::pair<double,double>> out;//创建一个 std::mt19937 类型的随机数生成器 mt,并使用当前时间的微秒数作为种子,以确保每次运行时生成的随机数序列不同std::mt19937 mt;mt.seed(std::chrono::system_clock::now().time_since_epoch().count());for(double i=begin;i<end;i=i+stride){// 使用 std::uniform_real_distribution<double>(0, 20) 生成一个在 0 到 20 之间的随机 double 值double y_=std::uniform_real_distribution<double>(0,20)(mt);// 将随机值 y_ 与通过调用 fun(i) 得到的值相加y_=y_+fun(i);out.push_back(std::make_pair(i,y_));}return out;
}//y=A*exp(x)+B*sinx+C*x^3,  A=0.02,B=3.2,C=1.1,D=3
struct my_ceres_test{
public:my_ceres_test(double x,double y):x_(x),y_(y){}template<typename T>bool operator()(const T* const A, const T* const B, const T* const C,const T* const D, T* residual)const{residual[0]=y_-A[0]*exp(x_)-B[0]*sin(x_)-C[0]*pow(x_,D[0]);return true;}
private:double x_;double y_;
};int main(int argc,char** argv){google::InitGoogleLogging(argv[0]);ceres::Problem problem;double A=0.0, B=0.0, C=0.0, D=1.0;double begin=1.0, end=10.0, stride=0.02;std::vector<std::pair<double,double>> datas = measurement_data_generation(begin, end, stride, function);std::cout << "\n test data sum: " << datas.size() <<" \n" << std::endl;for(auto data_:datas){ceres::CostFunction *cost_function=new ceres::AutoDiffCostFunction<my_ceres_test,1,1,1,1,1>(new my_ceres_test(data_.first,data_.second));problem.AddResidualBlock(cost_function,nullptr,&A,&B,&C,&D);}ceres::Solver::Options options;options.minimizer_progress_to_stdout=true;ceres::Solver::Summary summary;ceres::Solve(options, &problem, &summary);// std::cout<<summary.FullReport()<<std::endl;std::cout << summary.BriefReport() << "\n";std::cout<<" A = "<<A<<"\n B = "<<B<<"\n C = "<<C<<"\n D = "<<D<<std::endl;#ifdef MATPLOTstd::vector<double> x,y,y_;for(auto data_:datas){x.push_back(data_.first);y.push_back(data_.second);y_.push_back(A*exp(data_.first)+B*sin(data_.first)+C*pow(data_.first,D));}matplotlibcpp::figure_size(1200,800);matplotlibcpp::named_plot("$y=Ae^x+Bsinx+Cx^3+n$",x,y,"bx--");matplotlibcpp::named_plot("fitied,$y=\\hat{A}e^x+\\hat{B}sinx+\\hat{C}x^3$",x,y_,"r-");matplotlibcpp::legend();matplotlibcpp::grid(true);matplotlibcpp::title("my_ceres_test plot");matplotlibcpp::show();
#endifreturn 0;}

注意:取消上述代码 #define MATPLOT 注释,可使用 matplotlibcpp 工具进行数据可视化

matplotlibcpp 的源码安装:

# 先下载上述链接 matplotlibcpp源码
sudo apt-get install python3.8-dev
sudo apt-get install python3-dev
mkdir matplotlib-cpp-master/build && cd matplotlib-cpp-master/build
cmake ..
make -j4
sudo make install

CMakeLists.txt 如下:

cmake_minimum_required(VERSION 3.16)
project(my_test)
set(CMAKE_CXX_STANDARD 14)# Ceres库
find_package(Ceres REQUIRED)
include_directories(${CERES_INCLUDE_DIRS})# matplotcpp 依赖
find_package(PythonLibs REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS}
)add_executable(my_test_matplot my_test_matplot.cpp)
target_link_libraries(my_test_matplot ${CERES_LIBRARIES} ${PYTHON_LIBRARIES})

2.4 优化过程及结果
由图可知,测试数据共451组;Ceres最终找到的解决方案: A = 0.0239231 , B = 8.34126 , C = 1.70188 , D = 2.78483 A=0.0239231, B=8.34126, C=1.70188, D=2.78483 A=0.0239231,B=8.34126,C=1.70188,D=2.78483 目标函数值为 8832.095 8832.095 8832.095 (优化前目标函数值为 66298520 66298520 66298520)。
在这里插入图片描述

如下所示,使用 matplotlibcpp 进行数据可视化:
在这里插入图片描述

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

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

相关文章

基于Java作业管理系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f; 感兴趣的可以先收藏起来&#xff0c;…

Java——集合(一)

前言: Collection集合&#xff0c;List集合 文章目录 一、Collection 集合1.1 集合和数组的区别1.2 集合框架1.3 Collection 集合常用方法1.4 Collction 集合的遍历 二、List 集合2.1 List 概述2.2 List集合的五种遍历方式2.3 List集合的实现类 一、Collection 集合 1.1 集合和…

Vitis Accelerated Libraries 学习笔记--OpenCV 安装指南

目录 1. 简介 2. 安装过程 2.1 安装准备 2.2 编译并安装 XRT 2.2.1 下载 XRT 源码 2.2.2 安装依赖项 2.2.3 构建 XRT 2.2.4 打包 DEB 2.2.5 安装 XRT 2.3 编译并安装 OpenCV 2.3.1 下载 OpenCV 源码 2.3.2 创建目录 2.3.3 设置环境变量 2.3.4 构建 opencv 3. 总…

ping命令返回结果实例分析

测试在各相关情况下ping命令回复信息。 网络环境搭建如下图所示&#xff1a; 【1】R1、R2、PC1和PC2没有配置&#xff0c;测试ping命令回复 在路由器没有配置端口IP地址和路由&#xff0c;PC没有配置IP地址、子网掩码和网关的情况下&#xff0c;PC2 ping 192.168.1.1。 在PC没…

加速鸿蒙生态共建,蚂蚁mPaaS助力鸿蒙原生应用开发创新

6月21日-23日&#xff0c;2024华为开发者大会&#xff08;HDC 2024&#xff09;如期举行。在22日的【鸿蒙生态伙伴SDK】分论坛中&#xff0c;正式发布了【鸿蒙生态伙伴SDK市场】&#xff0c;其中蚂蚁数科旗下移动开发平台mPaaS&#xff08;以下简称&#xff1a;蚂蚁mPaaS&#…

QtCreator/VS中制作带有界面的动态库

1、首先创建动态库项目 class UNTITLED25_EXPORT Untitled25 {public:Untitled25(); };2、直接右键创建同名窗口类进行覆盖 3、引入global头文件并添加到处宏</

【SSM】

Spring常见面试题总结 Spring 基础 什么是 Spring 框架? Spring 是一款开源的轻量级 Java 开发框架&#xff0c;旨在提高开发人员的开发效率以及系统的可维护性。 我们一般说 Spring 框架指的都是 Spring Framework&#xff0c;它是很多模块的集合&#xff0c;使用这些模块…

转让神州开头的无区域科技公司需要多少钱

您好&#xff0c;我公司现有2家无区域神州名称的公司转让。所谓无区域名称是公司名称中不带有行政区划、及行业特点的公司名称&#xff0c;都是需要在工商总,局核准名称的&#xff0c;对于民营企业来说也比较喜欢这种名称名称很大气&#xff0c;现在重核更严格了&#xff0c;所…

Docker如何安装redis

目录 1. 拉取redis的镜像文件 2. 创建redis的容器卷 3. 准备reids的配置文件 4. 以配置文件启动redis 1. 拉取redis的镜像文件 # 默认安装最新版本 如果需要指定版本 docker pull redis:版本号 docker pull redis 详细版本请看dockerhub的官网&#xff1a; hub.docker…

MySQL中的ibd2sdi—InnoDB表空间SDI提取实用程序

ibd2sdi 是一个用于从 InnoDB 表空间文件中提取序列化字典信息&#xff08;Serialized Dictionary Information, SDI&#xff09;的实用程序。这个实用程序可以用于提取存储在持久化 InnoDB 表空间文件中的 SDI 数据。 可以对以下类型的表空间文件使用 ibd2sdi&#xff1a; 每…

DDS信号的发生器(验证篇)——FPGA学习笔记8

前言&#xff1a;第一部分详细讲解DDS核心框图&#xff0c;还请读者深入阅读第一部分&#xff0c;以便理解DDS核心思想 三刷小梅哥视频总结&#xff01; 小梅哥https://www.corecourse.com/lander 一、DDS简介 DDS&#xff08;Direct Digital Synthesizer&#xff09;即数字…

OneNote for Windows 10 下载

OneNote for Windows 10 安装 1.在浏览器中输入地址&#xff1a;https://apps.microsoft.com/detail/9wzdncrfhvjl?hlzh-cn&glUS2OneNote for Windows 10 - 在 Windows 上免费下载并安装 |Microsoft StoreOneNote 是用于在设备上捕获和组织你的一切内容的数字笔记本。快速…

BUG cn.bing.com 重定向的次数过多,无法搜索内容

BUG cn.bing.com 重定向的次数过多&#xff0c;无法搜索内容 环境 windows 11 edge浏览器详情 使用Microsoft Edge 必应搜索显示"cn.bing.com"重定向次数过多&#xff0c;无法进行正常的检索功能 解决办法 检查是否开启某些科_学_上_网&#xff08;翻_墙&#xf…

轻松重命名Windows用户Users目录下的文件夹名称

设置系统还原点 为避免设置失败&#xff0c;需提前准备好系统还原点以备份恢复系统。 打开系统属性&#xff1a; 在“系统保护”选项卡中&#xff0c;选择你想要保护的系统驱动器&#xff08;通常是C:驱动器&#xff09;。 点击“配置”按钮。 在弹出的窗口中&#xff0c;选…

【Python机器学习】NMF——将NMF应用于模拟信号数据

假设我们对一个信号感兴趣&#xff0c;它是由三个不同信号源合成的&#xff1a; import matplotlib.pyplot as plt import mglearnSmglearn.datasets.make_signals() plt.figure(figsize(6,1)) plt.plot(S,-) plt.xlabel(Time) plt.ylabel(Signal) plt.show()不幸的是&#xff…

大厂面试官问我:布隆过滤器有不能扩容和删除的缺陷,有没有可以替代的数据结构呢?【后端八股文二:布隆过滤器八股文合集】

往期内容&#xff1a; 面试官问我&#xff1a;Redis处理点赞&#xff0c;如果瞬时涌入大量用户点赞&#xff08;千万级&#xff09;&#xff0c;应当如何进行处理&#xff1f;【后端八股文&#xff08;1&#xff09;】-CSDN博客 本文为【布隆过滤器八股文合集】初版&#xff0c…

数据结构:冒泡排序,选择排序,插入排序,希尔排序的实现分析

✨✨小新课堂开课了&#xff0c;欢迎欢迎~✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;数据结构与算法 小新的主页&#xff1a;编程版小新-CSDN博客 1.冒泡排序 1.1算法思想 冒泡排序的基本思想就是&a…

字节跳动:从梦想之芽到参天大树

字节跳动掌舵人&#xff1a;张一鸣 2012年&#xff1a;梦想的起点&#xff1a;在一个阳光明媚的早晨&#xff0c;北京的一座普通公寓里&#xff0c;一位名叫张一鸣的年轻人坐在电脑前&#xff0c;眼中闪烁着坚定的光芒。他的心中有一个梦想——通过技术改变世界&#xff0c;让…

嵌入式实验---实验六 I2C传输实验

一、实验目的 1、掌握STM32F103I2C传输程序设计流程&#xff1b; 2、熟悉STM32固件库的基本使用。 二、实验原理 1、本案例利用I/O端口通过KEY01按键来控制STM32F103R6向24C02写入“hello”&#xff0c;通过另外一个按键KEY02来控制STM32F103R6从24C02读取“hello”&#x…

又一个前后端分离的整合了OpenAI大模型的高并发、高性能和可扩展的项目完结了,写到简历上,嘎嘎强!

大家好&#xff0c;我是冰河~~ 经过四个多月的坚持&#xff0c;《分布式IM即时通讯系统》终于完结了&#xff0c;也感谢大家这四个多月以来的坚持和陪伴&#xff0c;也相信大家在《分布式IM即时通讯系统》专栏中&#xff0c;学到了不少知识和技术。接下来&#xff0c;我们就一…