使用gsl做最小二乘法的非线性拟合

拟合的函数方程是
y=alpha*exp(-kappa*x);

拟合后能正确算出alpha和kappa的值,用gsl写这个玩意好啰嗦,用python的curve_fit10行代码就能搞定。

  1. type
  2. PFitData=^TFitData;
  3. TFitData=record
  4. t:Pdouble;
  5. y:Pdouble;
  6. n:Integer;
  7. end;
  8.  
  9. function market(alpha,kappa, t:double):double;
  10. begin
  11. result:=alpha*exp(-kappa*t);
  12. end;
  13.  
  14. function func_f(x: Pgsl_vector; params: Pointer; f: Pgsl_vector): Integer;cdecl;
  15. var
  16. data:PFitData;
  17. alpha:double;
  18. kappa:double;
  19. i:Integer;
  20. t,yi,y:double;
  21. begin
  22. data:= PFitData(params);
  23. alpha := gsl_vector_get(x, 0);
  24. kappa := gsl_vector_get(x, 1);
  25.  
  26. for I := 0 to data^.n-1 do
  27. begin
  28. t := data^.t[i];
  29. yi := data^.y[i];
  30. y := market(alpha,kappa, t);
  31.  
  32. gsl_vector_set(f, i, yi - y);
  33. end;
  34.  
  35.  
  36. Result:= Ord(GSL_SUCCESS);
  37. end;
  38.  
  39.  
  40. procedure TFormMain.btnASClick(Sender: TObject);
  41. var
  42. fdf:gsl_multifit_nlinear_fdf;
  43.  
  44. n:Integer;
  45.  
  46. p:Integer;
  47.  
  48. x:pgsl_vector;
  49. fdf_params:gsl_multifit_nlinear_parameters;
  50. r:pgsl_rng;
  51.  
  52. i:Integer;
  53.  
  54. t:double;
  55. fit_data:TFitData;
  56.  
  57. alpha,kappa:double;
  58.  
  59. tp:pgsl_multifit_nlinear_type;
  60. gsl_multifit_nlinear_trs_lmaccel2:function():Pgsl_multifit_nlinear_trs;cdecl;
  61.  
  62. gsl_vector_set2:procedure (v: Pgsl_vector; i: NativeUInt; x: Double); cdecl;
  63. begin
  64. n:=300; //number of data points to fit
  65. p:=2; //parameters count
  66.  
  67.  
  68. x := gsl_vector_alloc(p);
  69.  
  70. fdf_params :=gsl_multifit_nlinear_default_parameters();
  71.  
  72. GetMem(fit_data.t, n * sizeof(double));
  73. GetMem(fit_data.y, n * sizeof(double));
  74. fit_data.n := n;
  75.  
  76. //generate simulate data
  77. for I := 0 to n-1 do
  78. begin
  79. t:=i/n;
  80. fit_data.t[i]:=t;
  81. fit_data.y[i]:=market(3,4, t);
  82. end;
  83.  
  84. // /* define function to be minimized */
  85. FillChar(fdf, sizeof(gsl_multifit_nlinear_fdf),0);
  86. fdf.f := @func_f;
  87. fdf.df := nil;//func_df;
  88. fdf.fvv := nil;//func_fvv;
  89. fdf.n := n;
  90. fdf.p := p;
  91. fdf.params := @fit_data;
  92.  
  93. // /* starting point */
  94. gsl_vector_set(x, 0, 1.0);
  95. gsl_vector_set(x, 1, 1.0);
  96.  
  97. fdf_params.trs := gsl_multifit_nlinear_trs_lmaccel;
  98.  
  99.  
  100. // solve_system(x, &fdf, &fdf_params);
  101.  
  102. tp:=gsl_multifit_nlinear_trust;
  103.  
  104. var max_iter:Integer := 200;
  105. var xtol:double := 1.0e-8;
  106. var gtol:double := 1.0e-8;
  107. var ftol:double := 1.0e-8;
  108.  
  109. //fdf_params.trs^.alloc(@fdf,n,p);
  110. var work:pgsl_multifit_nlinear_workspace := gsl_multifit_nlinear_alloc(tp, @fdf_params, n, p);
  111.  
  112. var f2:pgsl_vector := gsl_multifit_nlinear_residual(work);
  113. var y:pgsl_vector := gsl_multifit_nlinear_position(work);
  114.  
  115. var info:integer;
  116. var chisq0, chisq, rcond:double;
  117.  
  118. ///* initialize solver */
  119. gsl_multifit_nlinear_init(x, @fdf, work);
  120.  
  121. //* store initial cost */
  122. gsl_blas_ddot(f2, f2, @chisq0);
  123.  
  124. //* iterate until convergence */
  125. gsl_multifit_nlinear_driver(max_iter, xtol, gtol, ftol,
  126. nil, nil, @info, work);
  127.  
  128. //* store final cost */
  129. gsl_blas_ddot(f2, f2, @chisq);
  130.  
  131. //* store cond(J(x)) */
  132. gsl_multifit_nlinear_rcond(@rcond, work);
  133.  
  134. gsl_vector_memcpy(x, y);
  135.  
  136. gsl_multifit_nlinear_free(work);
  137.  
  138. alpha := gsl_vector_get(x, 0);
  139. kappa := gsl_vector_get(x, 1);
  140.  
  141.  
  142. gsl_vector_free(x);
  143.  
  144. end;