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

news2024/11/20 20:37:54

文章目录

  • 一、曲线方程
    • 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 进行数据可视化:
在这里插入图片描述

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

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

相关文章

Windows程序设计课程作业-3(文件并发下载)

目录 目录 1.作业内容 2.作业要求 3.主要思路 1&#xff09;窗体和组件初始化 2&#xff09;下载管理器实例化 3&#xff09;按钮点击事件处理 4&#xff09;窗体加载事件处理 5&#xff09;下载消息处理 4.主要难点 1&#xff09;多线程管理&#xff1a; 2&#xff09…

智能优化算法改进策略之局部搜索算子(六)--进化梯度搜索

1、原理介绍 进化梯度搜索(Evolutionary Gradient Search, EGS)[1]是兼顾进化计算与梯度搜索的一种混合算法&#xff0c;具有较强的局部搜索能力。在每次迭代过程中&#xff0c;EGS方法首先用受进化启发的形式估计梯度方向&#xff0c;然后以最陡下降的方式执行实际的迭代步骤&…

【JavaSE ⑧】P219 ~ 225 Date类‘’DateFormat类转化Date和字符串;Calendar类获得日历中某值,修改日历,日历转日期

目录 日期时间类1 Date类概述常用方法 2DateFormat类构造方法格式规则常用方法parse方法format方法 3 Calendar类概念获取方式常用方法get/set方法add方法getTime方法 ● 练习1.判断Date不同参数构造的输出2. 用日期时间相关的API&#xff0c;计算一个人已经出生了多少天。3. 获…

【Java】已解决java.lang.NoSuchMethodException异常

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决java.lang.NoSuchMethodException异常 在Java编程中&#xff0c;java.lang.NoSuchMethodException是一个常见的运行时异常&#xff0c;它通常表示尝试通过反射调用一个不存在…

Ai调教写作技巧,不会还有人在到处找指令吧!一篇文章带你学会生成爆款文章写作指令

大家好&#xff0c;我是网创有方的站长&#xff0c;今天教大家一个重磅级的ai调价指令。 相信很多朋友们都去到处找过写作指令&#xff0c;包括我之前也是&#xff0c;但是随着运用ai写作的次数越来越多&#xff0c;我也是渐渐地熟悉了ai的调教。那么本文的目的是什么呢&#…

使用obdumper对oceanbase进行备份,指定2881端口

1.安装obdumper &#xff08;1&#xff09;下载软件 OceanBase分布式数据库-海量数据 笔笔算数https://www.oceanbase.com/softwarecenter &#xff08;2&#xff09;安装软件 参考&#xff1a;https://www.oceanbase.com/docs/common-oceanbase-dumper-loader-100000000062…

C语言标准库

目录 引言 一、C标准库概述 常用标准库函数 字符串处理 数学运算 动态内存分配 标准库的扩展与限制 扩展功能 使用限制 使用自定义库与第三方库 创建自定义库 使用第三方库 表格总结 标准库头文件及功能 常用标准库函数 总结 引言 C标准库是C编程语言的重要组成…

Android studio登录Google账号超时的解决方法

确保自己已经打开了代理&#xff08;科学上网&#xff09;在设置-外观与行为-系统设置-HTTP代理 中打开“自动检测代理设置”&#xff1a; 再次重新尝试登录Google账号&#xff0c;登陆成功&#xff01; 学术会议征稿 想要了解国内主办的覆盖学科最全最广的学术会议&#xff0c…

redis持久化操作【随记】

持久化 Redis它是将数据保存到内存当中,内存里的数据最大特点: 断电易失.保存在内存的数据就没有了.如果如果这些数据还有用,业务使用啥的,不能就让它这么没有了. redis当中提供持久化机制, 说白了,将内存的数据 —-> 写入到磁盘. –> 持久化. 1 rdb方式 redis database,…

帕金森患者饮食指南:科学调养,呵护健康

&#x1f33c;在医学的广阔领域中&#xff0c;帕金森病作为一种慢性神经系统疾病&#xff0c;除了需要专业的医疗治疗外&#xff0c;日常饮食的调养也显得尤为重要。 今天&#xff0c;就为大家带来一份专为帕金森患者打造的饮食建议&#xff0c;希望能为大家的健康调养提供一些…

泛微E9与金蝶云星空ERP的无缝集成案例详解(包括接口与字段)

业务系统现状 背景介绍 泛微E9和金蝶云星空ERP是两款广泛应用与企业管理的信息系统&#xff0c;分别在移动办公自动化和企业资源计划管理领域占据重要地位。然而企业在使用这些系统时往往面临着信息孤岛和系统孤立的问题&#xff0c;导致数据无法在不系统之间高效流转共享。 当…

微服务——服务治理

目录 1 什么是服务治理&#xff1f;2 为什么需要服务治理&#xff1f;3 服务治理的关键点3.1 服务注册与发现3.2 负载均衡3.3 容错与熔断3.4 服务监控与告警3.5 服务配置管理 4 示例说明5 总结 1 什么是服务治理&#xff1f; 简单来说&#xff0c;服务治理就是对微服务架构中的…

Java:113-Spring Data JPA详解

Spring Data JPA详解 Spring Data Jpa 是应用于Dao层的⼀个框架&#xff0c;简化数据库开发的&#xff0c;作用和Mybatis框架⼀样&#xff0c;但是在使用方式和底层机制是有所不同的&#xff0c;最明显的⼀个特点&#xff0c;Spring Data Jpa 开发Dao的时候&#xff0c;很多场景…

气膜建筑:持久耐用的建筑选择—轻空间

随着科技的发展&#xff0c;气膜建筑以其快速施工、节能环保和灵活多用的特点&#xff0c;正在各个领域获得越来越多的应用。然而&#xff0c;许多人对气膜建筑的耐用程度仍存有疑虑。本文将从气膜建筑的材料、结构设计和维护等方面&#xff0c;深入探讨气膜建筑的耐用性&#…

【Android WebView】WebView基础

一、简介 WebView是一个基于webkit引擎、展现web页面的控件。Android的Webview在低版本和高版本采用了不同的webkit版本内核&#xff0c;4.4后直接使用了Chrome。 二、重要类 以WebView类为基础&#xff0c;WebSettings、WebViewClient、WebChromeClient为辅助共同完成安卓段加…

阿里云,大周末彻底要爆!

大家好&#xff0c;我是肉哥&#xff0c;熟悉我的人都知道&#xff0c;每年6.18我都会带领大家薅阿里云的羊毛&#xff0c;今年也不例外&#xff0c;作为程序员搞台ECS&#xff0c;做个项目满满的成就感&#xff01;阿里内部小伙伴透漏&#xff0c;今年的618活动优惠力度更是拉…

FlinkCDC pipeline模式 mysql-to-paimon.yaml

flinkcdc 需要引入&#xff1a; source端&#xff1a; flink-cdc-pipeline-connector-mysql-xxx.jar、mysql-connector-java-xxx.jar、 sink端&#xff1a; flink-cdc-pipeline-connector-paimon-xxx.jar flinkcdc官方提供connect包下载地址&#xff0c;pipeline模式提交作业和…

成章数据库安装体验

对标Redis的国产数据库 一位来自国产数据库的朋友想请我试用一下他们的产品。并且直言早期问题比较多&#xff0c;还请多多包涵。一般对于这种比较客观和友好的我都愿意试试。对于怼天怼地吊打谁的我个人就不尝试了。 他们中文名字叫“成章数据库“我就尝试从一个不了解产品的…

Qt底层原理:深入解析QWidget的绘制技术细节(1)

在Qt5中&#xff0c;QWidget的绘制流程比较分散&#xff0c;网上介绍的文章也很少&#xff0c;因此写一篇文章总结记录一下这部分的知识点。 笔者使用的是Qt5.15.2的源码。 基本的绘制流程&#xff1a;从update到合成 更新请求&#xff08;Invalidate&#xff09;: 当一个QWidg…

线程间通信方式(互斥(互斥锁)与同步(无名信号量、条件变量))

1通信机制&#xff1a;互斥与同步 线程的互斥通过线程的互斥锁完成&#xff1b; 线程的同步通过无名信号量或者条件变量完成。 2 互斥 2.1 何为互斥&#xff1f; 互斥是在多个线程在访问同一个全局变量的时候&#xff0c;先让这个线程争抢锁的资源&#xff0c;那个线程争抢…