非线性最小二乘数据拟合

Introduction

用最小二乘法解决实际问题包含两个基本环节: 

先根据所给资料点的变化趋势与问题的实际背景确定函数,即确定用来拟合未知函数的拟合函数所具有的形式
然后 按最小二乘原则“使残差平方和最小”求最小二乘解出函数形式,即确定函数的待定系数:参数

但在实际问题中所选取的拟合函数经常是双曲线形式、指数函数形式等含待定参数的非线性函数
这将导致求解非线性方程组

Alogrithm

参考  非线性最小二乘法的一种迭代解法

非线性最小二乘数据拟合_第1张图片

可以知道下一次跌代时使用的bj 为

bj = inv(A'*A) * A' * (y-f) + bj0

这是整个算法的核心
下面使用c语言实现

Implement

用c语言实现的关键是要求出 偏导,以及矩阵的相关运算(转置,求逆,相乘),重点是求逆

矩阵求逆:

由定义,先求出矩阵的行列式,再求出矩阵的伴随矩阵
double Determinant (double a[NUM][NUM], int n) { // get the determinant
    if (n == 1) return a[0][0];
    double result = 0;
    double tmp[NUM][NUM];
    int i, j, k;

    for (i=0; i=i)?(k+1):k]; 
        double itera = Determinant(tmp, n-1); // iteraction
        if (i%2 == 0) // 偶数行系数为正
            result += a[0][i]*itera;
        else
            result -= a[0][i]*itera;
    }
    return result;
}

void Adjoint (double a[NUM][NUM], int n, double aj[NUM][NUM]) { //get the adjoint matrix
    int i, j, k, t;
    if (n == 1) {
        aj[0][0] = 1;
        return;
    }
    double tmp[NUM][NUM];
    for (i=0; i=i?(k+1):k][t>=j?(t+1):t];
            aj[j][i] = Determinant(tmp, n-1);
            if ((i+j)%2 == 1) {
                aj[j][i] = -aj[j][i];
            }
        }
    }
}

 伴随矩阵除以行列式就是逆矩阵

偏导

首先写求导 , 按定义  ( f(x+EPS) - f(x) ) / EPS
下面对高斯函数的三个参数求偏导得到Jacoiban A : 
double Gauss (double a, double b, double c, double x) {
    return a*exp(-(x-b)*(x-b)/(c*c));
}

double ADerivative (double (*Gauss)(double,double,double,double),
                   double a, double b, double c, double x) {
    return ((*Gauss)(a+EPS, b, c, x)-(*Gauss)(a, b, c, x))/EPS;
}
double BDerivative (double (*Gauss)(double,double,double,double),
                   double a, double b, double c, double x) {
    return ((*Gauss)(a, b+EPS, c, x)-(*Gauss)(a, b, c, x))/EPS;
}
double CDerivative (double (*Gauss)(double,double,double,double),
                   double a, double b, double c, double x) {
    return ((*Gauss)(a, b, c+EPS, x)-(*Gauss)(a, b, c, x))/EPS;
}

注:函数名作为另一个函数的参数调用方法:
参见另一篇文章c语言函数指针

你可能感兴趣的:(c语言,算法)