# Curve Fitting

到目前为止，我们看到的例子都是没有数据的简单优化问题。最小二乘法和非线性最小二乘法的最初目的是对数据进行曲线拟合。我们使用曲线方程 $$y=e^{0.3x+0.1}$$ 来生成样本数据，并且对每个样本都添加一个标准差为 $$\sigma=0.2$$ 的高斯噪声，我们来拟合如下曲线方程：

$$
y=e^{mx+c}
$$

其中 $$m,c$$ 使我们要通过样本进行估计的参数。和前面一样，第一步仍然是定义一个模板函数去评估每一个参数块的残差，这里有多少个样本就有多少个残差项，但是每个残差项的 Cost 计算方式和 ParameterBlock 的维度都是一样的。

```cpp
struct ExponentialResidual {
  ExponentialResidual(double x, double y)
      : x_(x), y_(y) {}

  template <typename T>
  bool operator()(const T* const m, const T* const c, T* residual) const {
    residual[0] = y_ - exp(m[0] * x_ + c[0]);
    return true;
  }

 private:
  // Observations for a sample.
  const double x_;
  const double y_;
};
```

假定观测数据存放在一个 2n 大小的数组中，我们称为 data。然后进行优化问题的构造，就是为每个观测创建一个 CostFunction。

```cpp
double m = 0.0;
double c = 0.0;

Problem problem;
for (int i = 0; i < kNumObservations; ++i) {
  CostFunction* cost_function =
       new AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>
           (data[2 * i], data[2 * i + 1]);
  problem.AddResidualBlock(cost_function, nullptr, &m, &c);
}
```

编译并运行 [examples/curve\_fitting.cc](https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/curve_fitting.cc) 可以得到如下结果：

```cpp
iter      cost      cost_change  |gradient|   |step|    tr_ratio  tr_radius  ls_iter  iter_time  total_time
   0  1.211734e+02    0.00e+00    3.61e+02   0.00e+00   0.00e+00  1.00e+04       0    5.34e-04    2.56e-03
   1  1.211734e+02   -2.21e+03    0.00e+00   7.52e-01  -1.87e+01  5.00e+03       1    4.29e-05    3.25e-03
   2  1.211734e+02   -2.21e+03    0.00e+00   7.51e-01  -1.86e+01  1.25e+03       1    1.10e-05    3.28e-03
   3  1.211734e+02   -2.19e+03    0.00e+00   7.48e-01  -1.85e+01  1.56e+02       1    1.41e-05    3.31e-03
   4  1.211734e+02   -2.02e+03    0.00e+00   7.22e-01  -1.70e+01  9.77e+00       1    1.00e-05    3.34e-03
   5  1.211734e+02   -7.34e+02    0.00e+00   5.78e-01  -6.32e+00  3.05e-01       1    1.00e-05    3.36e-03
   6  3.306595e+01    8.81e+01    4.10e+02   3.18e-01   1.37e+00  9.16e-01       1    2.79e-05    3.41e-03
   7  6.426770e+00    2.66e+01    1.81e+02   1.29e-01   1.10e+00  2.75e+00       1    2.10e-05    3.45e-03
   8  3.344546e+00    3.08e+00    5.51e+01   3.05e-02   1.03e+00  8.24e+00       1    2.10e-05    3.48e-03
   9  1.987485e+00    1.36e+00    2.33e+01   8.87e-02   9.94e-01  2.47e+01       1    2.10e-05    3.52e-03
  10  1.211585e+00    7.76e-01    8.22e+00   1.05e-01   9.89e-01  7.42e+01       1    2.10e-05    3.56e-03
  11  1.063265e+00    1.48e-01    1.44e+00   6.06e-02   9.97e-01  2.22e+02       1    2.60e-05    3.61e-03
  12  1.056795e+00    6.47e-03    1.18e-01   1.47e-02   1.00e+00  6.67e+02       1    2.10e-05    3.64e-03
  13  1.056751e+00    4.39e-05    3.79e-03   1.28e-03   1.00e+00  2.00e+03       1    2.10e-05    3.68e-03
Ceres Solver Report: Iterations: 13, Initial cost: 1.211734e+02, Final cost: 1.056751e+00, Termination: CONVERGENCE
Initial m: 0 c: 0
Final   m: 0.291861 c: 0.131439
```

从 $$m=0,c=0$$ 为初值进行优化，目标函数值为 1.211734e+02。最终 Ceres 找到的解为 $$m=0.291861,c=0.131439$$，目标函数值为 1.056。和真值 $$m=0.3,c=0.1$$ 比起来有略微的差别，但是由于噪声的存在，结果其实在可接受的范围内。实际上，如果用$$m=0.3,c=0.1$$ 来评估目标函数会发现 Cost 比 1.056 还要大。下图展示了拟合结果。

<figure><img src="/files/3PTisiI67KlhyEEqgWt6" alt="" width="563"><figcaption><p>Least Square Curve Fitting</p></figcaption></figure>

## Footnotes

* [examples/curve\_fitting.cc](https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/curve_fitting.cc)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ceres-solver-tutorial-cn.gitbook.io/ceres/optimization-tutorial/non-linear-least-squares/curve-fitting.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
