C++ 莱文伯格&x2013;马夸特不收敛

C++ 莱文伯格&x2013;马夸特不收敛,c++,numerical-methods,levenberg-marquardt,C++,Numerical Methods,Levenberg Marquardt,我尝试根据数值公式,使用Levenberg-marquardt的方法来拟合模型。 问题是:它不收敛,或者当它收敛时,它不精确。。。或者至少协变矩阵是奇怪的 int i=0; for (i = 0; i < 3e4; i++) { mrqmin(x, y, sig, NPCalib, a, ia, 3, covar, alpha, &chisk, afunc, &alamda);

我尝试根据数值公式,使用Levenberg-marquardt的方法来拟合模型。 问题是:它不收敛,或者当它收敛时,它不精确。。。或者至少协变矩阵是奇怪的

        int i=0;
        for (i = 0; i < 3e4; i++) {
            mrqmin(x, y, sig, NPCalib, a, ia, 3, covar, alpha, &chisk, afunc,
                &alamda);
            if (chisk < 1e-8)
                sumchisk++;
            if (sumchisk > 5)
                break;
            if (alamda > 1e8)
                alamda = 1e8;
        }
我将nr源代码改为使用double而不是float。没有使用第一个数组元素,因为它来自fortran代码,我不想更改这么小的细节

该模型还包含一个3。参数,该参数未在此拟合中使用,因此保持为[3]=-1,因为ia[3]=0。ia[]=1表示参数即将拟合

然而,现在我有一个问题,有时这并不收敛。它以
alamda=1e8
i=3e4
结束。尤其是当我将
chisk
lower设置为treshold时。
参数集似乎很好,但是。。。例如,chisk大约为1e-6,参数似乎很好,但从协变矩阵的对角线(应给出每个参数的平方标准偏差)来看,对于参数0.0001,存在一些类似于800000的红色

有人知道我在使用这个算法时做错了什么吗?
开始时,我需要在covar/alpha中写入任何特定内容?sig可以这样设置吗?

Gnu科学图书馆(GSL)有一个算法的实现:@madscietrict谢谢你的评论,但我认为nr2版本也可以工作。我不知道GSL是否会与我的数据有类似的问题,因为它可能是坏的条件。。。然而,我也觉得为非线性拟合解算器添加完整的GSL库有冲突。。。再加上我后来有了2-Dim。x-data,我需要调整源代码以适应它。对于nr2,这似乎工作得很好,但我不知道GSL的效果如何…使用调试器或添加一些打印。检查你的导数是否正确——将它们与数值导数进行比较。使用std::vector而不是挂起的数组指针。如果数组大小为常量,则不需要在堆上分配它们。就我所记得的,NR的实现对零梯度的反应不好。
double a[4] = {0.0, 0.0001, 100.0, -1};
int ia[4] = {0.0, 1, 1, 0};
double *x = {0.0, 799.157549545577, 799.92196995454, 800.683769692575};
double *y = {0.0, 524.26491, 525.26768, 526.26586};
double *sig = {0.0, 0.1*y[1], 0.1*y[2], 0.1*y[3]};
double **covar = new double*[4];    
covar[1] = new double[4];
covar[2] = new double[4];
covar[3] = new double[4];
double **alpha = new double*[4];    
alpha[1] = new double[4];
alpha[2] = new double[4];
alpha[3] = new double[4];
double chisk = 0;
double alamda = -1;

void afunc(int i, double x[], double a[], double *y, double dyda[], int ma)
{
    *y = a[1] * pow(x[i] + a[2], 2) / pow(1 + a[3] * CT[i - 1], 2);

    dyda[1] = pow(x[i] + a[2], 2) / pow(1 + a[3] * CT[i - 1], 2);
    dyda[2] = (2 * a[1] * (x[i] + a[2])) / pow
        (1 + a[3] * CalibTurn[i - 1], 2);
    dyda[3] = (-2 * a[1] * CT[i - 1] * pow(x[i] + a[2], 2)) / pow
        (1 + a[3] * CT[i - 1], 3);
}