14-QT5 GSL求解微分方程并结合qcustomplot绘图

22 篇文章 3 订阅
1. 所求微分方程

2 y ′ − y = 4 s i n ( 3 t ) , y ( 0 ) = y 0 , t ∈ [ 0 , 8 ] 2y′−y=4sin(3t),\quad y(0)=y0,\quad t \in [0,8] 2yy=4sin(3t),y(0)=y0,t[0,8]

2. GSL相关函数
  • 定义ODE系统:

       gsl_odeiv2_system
       
       // 所求函数
       int (* function) (double t, const double y[], double dydt[], void * params)
       // 所求函数的雅克比形式函数
       int (* jacobian) (double t, const double y[], double * dfdy, double dfdt[], void * params)
       // 微分方程阶数(纬度)
       size_t dimension
       // 其他参数
       void * params
    
    • 以前面定义求解的微分方程为例,写作如下代码(需要一阶导数前面的系数需要化为1):
 #include "math.h"
    int func (double t, const double y[], double f[],
          void *params)
    {
      (void)(t); /* avoid unused parameter warning */
      double mu = *(double *)params;
      f[0] = 2*sin(3*t)+y[0]/2;
      return GSL_SUCCESS;
    }
  • 可以计算出雅克比矩阵函数:
 int jac (double t, const double y[], double *dfdy,
         double dfdt[], void *params)
 {
      (void)(t); /* avoid unused parameter warning */
   double mu = *(double *)params;
      gsl_matrix_view dfdy_mat
        = gsl_matrix_view_array (dfdy, 1, 1);
      gsl_matrix * m = &dfdy_mat.matrix;
      gsl_matrix_set (m, 0, 0, 0.5);
    
      dfdt[0] = 0.0;
        
      return GSL_SUCCESS;
    }

  • 定义求解方法(driver)

    GSL中求解微分方程的方法有很多种,有常规步长的方法,有自适应步长控制的方法(Adaptive Step-size Control)以及进化方法(evolution),GSL支持的gsl_odeiv2_step_type有如下(参考GSL官方帮助手册第357页):

  - gsl_odeiv2_step_rk2
  - gsl_odeiv2_step_rk4
  - gsl_odeiv2_step_rkf45
    
  - gsl_odeiv2_step_rkck
    
  - gsl_odeiv2_step_rk8pd
    
  - gsl_odeiv2_step_rk1imp
    
  - gsl_odeiv2_step_rk2imp
    
  - gsl_odeiv2_step_rk4imp

  - gsl_odeiv2_step_bsimp

  - gsl_odeiv2_step_msadams

  - gsl_odeiv2_step_msbdf
  • 应用求解

    int gsl_odeiv2_driver_apply(gsl_odeiv2_driver * d, double * t, const double t1, double y[])

    • 参数1 *d:微分方程求解方法,gsl_odeiv2_driver类型
    • 参数2 *t:初始时刻
    • 参数3 t1:微分方程需要计算的时刻,该值是改变的
    • 参数4 y[]:含初始时刻t的初值,如果是二阶微分方程,其形式类似y[]={1,0}
3. qcustomplot绘图

自己编写一个函数,实现微分方程的求解以及绘图操作(省去了相关头文件及参数定义)

void MainWindow::setupQuadraticDemo(QCustomPlot *customPlot)
{
    QString demoName = "GSL ODE Demo";
    int len = 300;  // data length
    // generate some data:
    QVector<double> x(len), y(len); // initialize with entries 0..100

    // ---------------GLS ODE-------------------//
    double mu = NULL;
    gsl_odeiv2_system sys = {func, jac, 1, &mu};

    gsl_odeiv2_driver * d =
            gsl_odeiv2_driver_alloc_y_new (&sys, gsl_odeiv2_step_rk8pd,
                                           1e-6, 1e-6, 0.0);
    double t = 0.0, b = 10.0;
    double a = t;
    double y0[1] = { -24.0/37.0 };       // initial value at t is 1.0

    for (int i = 0; i <= len; i++)
    {
        double h = (b-a)/(double)len;
        double ti = a + i * h;
        int status = gsl_odeiv2_driver_apply (d, &t, ti, y0);

        if (status != GSL_SUCCESS)
        {
            printf ("error, return value=%d\n", status);
            break;
        }
        x.append(t);
        y.append(y0[0]);
//        printf ("%.5e %.5e\n", t, y0[0]);
    }

    gsl_odeiv2_driver_free (d);
    //====================END GSL ODE=====================

    // create graph and assign data to it:
    customPlot->addGraph();
    customPlot->graph(0)->setData(x, y);
    // give the axes some labels:
    customPlot->xAxis->setLabel("x");
    customPlot->yAxis->setLabel("y");
    // set axes ranges, so we see all data:
    customPlot->xAxis->rescale(true);
    customPlot->yAxis->rescale(true);
}
4. mainwindow.h完整代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "qcustomplot.h"	// 导入qcustomplot

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    void setupQuadraticDemo(QCustomPlot *customPlot);

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

5. mainwindow.cpp完整代码:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <stdio.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_odeiv2.h>
#include <gsl/gsl_sf_bessel.h>
#include "math.h"

// df/dt = 2sin(3t)+y/2
int func (double t, const double y[], double f[],
          void *params)
{
    (void)(t); /* avoid unused parameter warning */
    double mu = *(double *)params;
    f[0] = 2*sin(3*t)+y[0]/2;
    //    f[0] = t-1+1/t-2*y[0];
    return GSL_SUCCESS;
}

int jac (double t, const double y[], double *dfdy,
         double dfdt[], void *params)
{
    (void)(t); /* avoid unused parameter warning */
    double mu = *(double *)params;
    gsl_matrix_view dfdy_mat
            = gsl_matrix_view_array (dfdy, 1, 1);
    gsl_matrix * m = &dfdy_mat.matrix;
    gsl_matrix_set (m, 0, 0, 0.5);
    //     gsl_matrix_set (m, 0, 0, -2);

    //    dfdt[0] = 0.0;
    dfdt[1] = -1.0;

    return GSL_SUCCESS;
}


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    setupQuadraticDemo(ui->customPlot);
    setWindowTitle("QCustomPlot: GSL ODE Demo");
    statusBar()->clearMessage();
    //    currentDemoIndex = demoIndex;
    ui->customPlot->replot();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::setupQuadraticDemo(QCustomPlot *customPlot)
{
    int len = 300;  // data length
    // generate some data:
    QVector<double> x(len), y(len); // initialize with entries 0..100

    // ---------------GLS ODE-------------------//
    double mu = NULL;
    gsl_odeiv2_system sys = {func, jac, 1, &mu};

    gsl_odeiv2_driver * d =
            gsl_odeiv2_driver_alloc_y_new (&sys, gsl_odeiv2_step_rk8pd,
                                           1e-6, 1e-6, 0.0);
    double t = 0.0, b = 10.0;
    double a = t;
    double y0[1] = { -24.0/37.0 };       // initial value at t is 1.0

    for (int i = 0; i <= len; i++)
    {
        double h = (b-a)/(double)len;
        double ti = a + i * h;
        int status = gsl_odeiv2_driver_apply (d, &t, ti, y0);

        if (status != GSL_SUCCESS)
        {
            printf ("error, return value=%d\n", status);
            break;
        }
        x.append(t);
        y.append(y0[0]);
        //        printf ("%.5e %.5e\n", t, y0[0]);
    }

    gsl_odeiv2_driver_free (d);
    //====================END GSL ODE=====================

    // create graph and assign data to it:
    customPlot->addGraph();
    customPlot->graph(0)->setData(x, y);
    // give the axes some labels:
    customPlot->xAxis->setLabel("x");
    customPlot->yAxis->setLabel("y");
    // set axes ranges, so we see all data:
    customPlot->xAxis->rescale(true);
    customPlot->yAxis->rescale(true);
    //    customPlot->xAxis->setRange(-1, t1);
    //    customPlot->yAxis->setRange(-3, 3);
    //    customPlot->yAxis->scaleRange(1);
}

6. 注意事项
  • 导入qcustomplot之后pro文件需要支持printsupport:QT += widgets printsupport

  • pro文件需要导入GSL头文件路径以及库路径,以Linux为例:

    INCLUDEPATH += /usr/local/include
    LIBS += -L/usr/local/lib -lgsl -lgslcblas -lm
    
  • mainwindow.ui界面拖入一个widget控件,将其提升为QCustomPlot类,将控件名改为customPlot

  • 程序组织结构
    在这里插入图片描述

  • 实例结果显示:
    -在这里插入图片描述

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
GSL 开源 科学计算库 学习笔记(分享部分译稿) GSL是GNU Scientific Libary的简写,是一组专门为数值科学计算而设计的程序库。该程序库用C语言写就,C程序员提供了API。不过 可以对其使用swig工具进行封装,以便能被更高级的语言使用,比如C#,java等。读者可以在网上找到很多swig的例子。 GSL原码是以GPL协议发布的,获取与使用都非常地方便,这也是我们之所以选取GSL学习的根本原因。 GSL库涵盖了数值计算领域的方方面面,主要包括下面的计算领域,还有一些新的程序代码会不断纳入到GSL中。 Complex Numbers 复数; Roots of Polynomials 多项式求根; Special Functions 特殊函数; Vectors and Matrices 向量与距阵; Permutations 排列; Combinations 组合; Sorting 排序; BLAS Support 基础线性代数程序集(向量间运算,向量距阵运算,距阵间运算); Linear Algebra CBLAS Library 线性代数库; Fast Fourier Transforms 快速傅利叶变换; Eigensystems 特征值; Random Numbers 随机数; Quadrature 积分; Random Distributions 随机分布; Quasi-Random Sequences 近似随机分布序列; Histograms 直方图; Statistics 统计; Monte Carlo Integration Monte Carlo积分; N-Tuples N元组; Differential Equations 微分方程; Simulated Annealing 模拟退火算法; Numerical Differentiation 数值差分; Interpolation 拟合与插值; Series Acceleration; Chebyshev Approximations Chebyshev逼近; Root-Finding 求根; Discrete Hankel Transforms 离散Hankel转换; Least-Squares Fitting 最小二乘算法拟合; Minimization 最小值; IEEE Floating-Point IEEE浮点运输; Physical Constants 物理常量; Basis Splines 基本样条曲线; Wavelets 小波变换。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值