首页
统计
关于
Search
1
Win10安装mingw64配置最新版gcc与gfortran环境
607 阅读
2
李芒果空岛-1.20.1-发展记录-05
584 阅读
3
108第一届中国象棋比赛
541 阅读
4
Savitzky-Golay滤波器原理-01
535 阅读
5
史瓦西黑洞最内稳定圆轨道计算
500 阅读
默认分类
技术经验
工作学习
娱乐爱好
闲言碎语
登录
Search
标签搜索
天文
Minecraft
李芒果空岛
空间物理学
macOS
数值计算
非线性最小二乘
typecho
Python
GSL
gcc
迭代法
Fortran
Halo
朗谬尔波
Langmiur
环法自行车赛
短波通信
PTCG
Win10
Washy
累计撰写
76
篇文章
累计收到
1
条评论
首页
栏目
默认分类
技术经验
工作学习
娱乐爱好
闲言碎语
页面
统计
关于
搜索到
1
篇与
的结果
2023-03-29
非线性最小二乘法拟合函数-3
在前面两个博客中,推导得到了Levenberg-Marquardt算法(简称LM算法)的迭代公式,这里将讲述如何使用Fortran编写一个简单的LM算法。 此处介绍待定系数只有一个的情况。 1 程序设计 1.1 Levenberg_Maquardt_Fit 简介:LM算法子例程,输入离散数据,迭代拟合待定系数 传递参数: n 离散数据的长度 x 离散数据的自变量 y 离散数据的因变量 a 待定系数 1.2 myfunc 简介:待拟合函数的数值计算子例程。为了具有普适性,假定待拟合函数的解析式未知,函数结果只能由此子例程数值计算得到。 传递参数: n 离散数据的长度 x 离散数据的自变量 a 待定系数的当前值 fx 待拟合函数的数值计算结果 1.3 Calculate_Jacobian 简介:计算待拟合函数的Jacobian矩阵的子例程。为了具有普适性,使用差分法计算一阶导数。 传递参数: n 离散数据的长度 x 离散数据的自变量 y 待拟合函数的数值计算结果 a 待定系数的当前值 J 待拟合函数的Jacobian矩阵 2 源代码 2.1 Levenberg_Maquardt_Fit 此处迭代次数上限设置为30次,可根据需求自行更改 对于自变量有多个的情况,可将输入x改为x1,x2,...,满足自变量个数即可 SUBROUTINE Levenberg_Maquardt_Fit(n, x, y, a) IMPLICIT NONE ! 输入参数 INTEGER, INTENT(IN) :: n ! 数据点个数 REAL, DIMENSION(n), INTENT(IN) :: x, y ! 数据点 ! REAL, DIMENSION(3), INTENT(INOUT) :: a ! 待求的拟合系数 REAL, INTENT(INOUT) :: a ! 待求的拟合系数 ! 定义常量 INTEGER, PARAMETER :: m = 1 ! 待求的系数个数 REAL, PARAMETER :: eps = 1.0E-6 ! 收敛阈值 ! 定义变量 REAL :: da(m), r(n), J(n,m), H(m,m) ! 拟合系数、残差、雅可比矩阵、Hessian矩阵 REAL :: lambda, alpha(m) ! 调节因子、步长 INTEGER :: i, iter ! 循环计数器 REAL :: fx(n) ! 初始化调节因子 lambda = 0.001 ! 开始迭代 iter = 0 DO WHILE(iter < 30) ! 迭代次数上限为10000 iter = iter + 1 ! 计算被拟合函数值 CALL myfunc(n,x,a,fx) ! 计算残差向量 r = y - fx ! 计算雅可比矩阵 CALL Calculate_Jacobian(n, x, fx, a, J) ! 计算Hessian矩阵 H = MATMUL(TRANSPOSE(J), J) ! 计算梯度向量 da = MATMUL(TRANSPOSE(J), r) ! 计算搜索方向 DO i = 1, m H(i,i) = H(i,i) + lambda END DO ! CALL SOLVE_LINEAR_SYSTEM(m, H, da, alpha) alpha = da(1)/H(1,1) ! 计算新的拟合系数 a = a + alpha(1) ! 更新调节因子 IF (NORM2(r) < eps) THEN EXIT ELSE IF (NORM2(r) < NORM2(r - MATMUL(J, alpha))/2) THEN lambda = lambda/10. ELSE lambda = lambda*10. END IF END DO END SUBROUTINE 2.2 myfunc 此处使用了一个非常简单的一次函数作为示例,使用时需要将fx = a*x修改为实际的待拟合函数的形式。若待拟合函数是一个子例程,则在此处使用CALL调用 若在Levenberg_Maquardt_Fit子例程中修改了自变量个数,此处需要对应修改 SUBROUTINE myfunc(n,x,a,fx) IMPLICIT NONE ! 输入参数 INTEGER, INTENT(IN) :: n REAL, INTENT(IN) :: x(n) ! 自变量 REAL, INTENT(IN) :: a ! 拟合系数 REAL, INTENT(OUT) :: fx(n) fx = a*x END SUBROUTINE 2.3 Calculate_Jacobian 本子例程使用了差分法计算一阶导数,因此几乎适用于所有的待拟合函数 若在前面修改了自变量的个数,此处需对应修改 SUBROUTINE Calculate_Jacobian(n, x, y, a, J) IMPLICIT NONE ! 输入参数 INTEGER, INTENT(IN) :: n ! 数据点个数 REAL, DIMENSION(n), INTENT(IN) :: x, y ! 数据点 REAL, INTENT(IN) :: a ! 拟合系数 ! 输出参数 REAL, DIMENSION(n,1), INTENT(OUT) :: J ! 雅可比矩阵 ! 定义变量 INTEGER :: i ! 循环计数器 REAL :: dela, y1(n) ! 步进 dela = 0.01 ! 计算 a+dela 对应的 y1 CALL myfunc(n,x,a+dela,y1) ! 计算雅可比 DO i = 1, n J(i,1) = (y1(i) - y(i))/dela END DO END SUBROUTINE 3 测试 编写程序主体,设定y约为x的两倍,调用LM子例程计算待定系数a program name implicit none INTEGER n real :: x(5),y(5),a x = (/1.,2.,3.,4.,5./) y = (/2.1,4.1,5.9,8.1,9.9/) ! y = 2*x**2 + n = 5 a = 1.0 call Levenberg_Maquardt_Fit(n, x, y, a) print *,a end program name 使用gfortran编译生成可执行文件,运行可执行文件后,在终端打印出 1.99818182 离散数据的因变量约为自变量的两倍,因此上述计算结果符合预期
2023年03月29日
251 阅读
0 评论
0 点赞