【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 MATPLOT
    std::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();
#endif
    return 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 进行数据可视化:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

llm-universe | 四. 构建RAG应用

构建RAG应用 一.将LLM 接入 LangChain二.构建检索问答链1.加载向量数据库2.创建一个 LLM3.构建检索问答链4.检索问答链效果测试5.添加历史对话的记忆功能5.1 记忆&#xff08;Memory&#xff09;5.2 对话检索链&#xff08;ConversationalRetrievalChain&#xff09; 三. 部署知…

11-Django项目--Ajax请求二

目录 模版: demo_list.html perform_list.html 数据库操作: 路由: 视图函数: Ajax_data.py perform.py 模版: demo_list.html {% extends "index/index.html" %} {% load static %} # 未实现修改,删除操作{% block content %}<div class"container…

基于YOLOv8的多端车流检测系统(用于毕设+开源)

目录 ✨基于YOLOv8&#x1f680;的多端车流检测系统-MTAS (Multi-Platform Traffic Analysis System) 一、基本功能介绍 1、客户端 &#xff08;pyside6yolov8pytorch&#xff09; 2、网页端&#xff08;Vue3TypestriptPython3MySQL&#xff09; 3、创新点&#xff08;毕设需…

2024年最新通信安全员考试题库

61.架设架空光缆&#xff0c;可使用吊板作业的情况是&#xff08;&#xff09;。 A.在2.2/7规格的电杆与墙壁之间的吊线上&#xff0c;吊线高度5m B.在2.2/7规格的墙壁与墙壁之间的吊线上&#xff0c;吊线高度6m C.在2.2/7规格的电杆与电杆之间的吊线上&#xff0c;吊线高度…

【嵌入式 RT-Thread】一种优雅的使用 [互斥锁] 和 [信号量] 解决数据多路并发思路

rt-thread 中的信号量和互斥锁在工业开发项目中的应用&#xff0c;本博文主要介绍了一种优雅的使用 [互斥锁] 和 [信号量] 解决数据多路并发思路 2024-06 by 积跬步、至千里 目录 0. 个人简介 && 授权须知1. 工业场景描述1.1 工业数据采集需求1.2 总线协议与数据采集 2…

杭州代理记账报税全程托管专业实力全面指南

杭州代理记税报税服务可以为企业提供全程托管财务管理解决方案&#xff0c;确保企业的财务工作专业、高效、合规。以下是杭州代理记税报税服务全面指南&#xff1a; https://www.9733.cn/news/detail/185.html 一、代理记账报税服务的内容 基础服务&#xff1a; 每日记&#xf…

昇思25天学习打卡营第3天|张量Tensor

认识张量 张量&#xff0c;是一个数据结构&#xff0c;也可以说是一个函数&#xff0c;它描述了标量、矢量和张量之间线性关系。这些关系包括 内积、外积、线性映射以及笛卡尔积。张量中既有大小、又有方向。张量由多个数值构成&#xff0c;在n维空间里&#xff0c;会出现 n …

java对word文档预设参数填值并生成

目录 &#xff08;1&#xff09;定义word文档模板 &#xff08;2&#xff09;模板二次处理 处理模板图片&#xff0c;不涉及图片可以跳过 处理模板内容 &#xff08;3&#xff09;java对word模板填值 &#xff08;4&#xff09;Notepad的XML Tools插件安装 工作上要搞一个…

Yolo v5实现细节(2)

Yolo v5代码实现细节 IOU系列损失 在之前的yolo v3中我们使用的定位损失主要使用的是差值平方的形式&#xff0c;通过预测边界框的参数和真实边界框的参数来进行计算求解的。 定位损失 L loc ( t , g ) ∑ i ∈ pos ( σ ( t x i ) − g ^ x i ) 2 ( σ ( t y i ) − g ^ …

c语言学习记录(十)———函数

文章目录 前言一、函数的基本用法二、函数的参数传递1.基本方式2 数组在函数中的传参 前言 一个学习C语言的小白~ 有问题评论区或私信指出~ 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、函数的基本用法 函数是一个完成特定功能的代码模块&…

【Linux】锁|死锁|生产者消费者模型

&#x1f525;博客主页&#xff1a; 我要成为C领域大神&#x1f3a5;系列专栏&#xff1a;【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 ​ ​ 访问互斥 …

modelsim做后仿真的一点思路

这是以TD_5.6.3_Release_88061生成的网表文件&#xff08;其他工具生成的网表文件类似&#xff09;&#xff0c;与modelsim联合进行门级仿真的样例&#xff0c;时序仿真与门级仿真的方法类似&#xff0c;只是增加了标准延时文件。 1、建立门级仿真工程 将门级网表和testbench添…

深度学习31-33

1.负采样方案 &#xff08;1&#xff09;为0是负样本&#xff0c;负样本是认为构造出来的。正样本是有上下文关系 负采样的target是1&#xff0c;说明output word 在input word之后。 2.简介与安装 &#xff08;1&#xff09;caffe:比较经常用于图像识别&#xff0c;有卷积网…

一文详细了解Bootloader

Bootloader是什么 bootloader是一个引导加载程序&#xff0c;它的主要作用是初始化硬件设备、设置硬件参数&#xff0c;并加载操作系统内核。在嵌入式系统中&#xff0c;bootloader是硬件启动后第一个被执行的程序&#xff0c;它位于操作系统和硬件之间&#xff0c;起到桥梁的…

操作符详解(上) (C语言)

操作符详解&#xff08;上&#xff09; 一. 进制转换1. 二进制2. 二进制的转换 二. 原码 补码 反码三. 操作符的分类四. 结构成员访问操作符1. 结构体的声明2. 结构体成员访问操作符 一. 进制转换 1. 二进制 在学习操作符之前&#xff0c;我们先了解一些2进制、8进制、10进制…

魔众一物一码溯源防伪系统——守护品牌,守护信任!

在这个充满竞争的市场上&#xff0c;如何确保你的产品不被仿冒&#xff0c;如何赢得消费者的信任&#xff1f;魔众一物一码溯源防伪系统&#xff0c;为你提供一站式解决方案&#xff0c;守护你的品牌&#xff0c;守护消费者的信任&#xff01; &#x1f50d;魔众一物一码溯源防…

Node.js全栈指南:浏览器显示一个网页

上一章&#xff0c;我们了解到&#xff0c;如何通过第二章的极简 Web 的例子来演示如何查看官方文档。为什么要把查阅官方文档放在前面的章节说明呢&#xff1f;因为查看文档是一个很重要的能力&#xff0c;就跟查字典一样。 回想一下&#xff0c;我们读小学&#xff0c;初中的…

防火墙双机热备

防火墙双机热备 随着移动办公、网上购物、即时通讯、互联网金融、互联网教育等业务蓬勃发展&#xff0c;网络承载的业务越来越多&#xff0c;越来越重要。所以如何保证网络的不间断传输成为网络发展过程中急需解决的一个问题。 防火墙部署在企业网络出口处&#xff0c;内外网之…

windows系统修改克隆虚拟机的SID(报错:尝试将此计算机配置为域控制器时出错)

当我们用克隆虚拟机加入域的时候&#xff0c;可能会出现图下所示报错。这时我们可以用微软自带的工具sysprep来修改机器的SID来解决该问题 注意&#xff1a;用sysprep修改SID之后&#xff0c;系统会自动重启&#xff0c;之前配置好的网络、修改过的机器名会重置。所以&#xff…

6.2 通过构建情感分类器训练词向量

在上一节中&#xff0c;我们简要地了解了词向量&#xff0c;但并没有去实现它。在本节中&#xff0c;我们将下载一个名为IMDB的数据集(其中包含了评论)&#xff0c;然后构建一个用于计算评论的情感是正面、负面还是未知的情感分类器。在构建过程中&#xff0c;还将为 IMDB 数据…