我可以使用ceres求解器来拟合动态创建的曲线吗?

时间:2019-10-11 18:20:08

标签: c++ optimization curve-fitting least-squares ceres-solver

我需要将数据拟合到用户选择的曲线作为预定义函数的总和。这个想法是创建类似于peak-o-mat对光谱数据所做的操作。

示例: 将某些数据拟合为一个线性函数(两个参数)和一个柯西函数(两个参数)之和的函数。

如果在编译时知道我要拟合的曲线是线性和柯西的和,则可以为此创建一个特定的残差。但是问题是我只在运行时知道它。

我想做的是:

1)根据我向用户展示的功能列表定义残差:

struct Residual {
  Residual(double x, double y) : m_x(x), m_y(y) {}

 protected:
  // Observations for a sample.
  const double m_x;
  const double m_y;
};

struct LorentzianResidual : Residual {
  LorentzianResidual(double x, double y) : Residual(x, y) {}

  template <typename T>
  bool operator()(const T* const m, const T* const c, T* residual) const {
    residual[0] = T(m_y) - (1 / M_PI) * (0.5 * c[0]) /
                               ((T(m_x) - m[0]) * (T(m_x) - m[0]) +
                                (0.5 * c[0]) * (0.5 * c[0]));
    return true;
  }
};

struct LinearResidual : Residual {
  LinearResidual(double x, double y) : Residual(x, y) {}

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

2)根据用户选择的功能组合来解决ceres::Problem添加残差块的情况。

我在想两个选择:

a)创建一个曲线拟合类,其成员具有所有选定的函数以及每个函数的参数数组。然后,我将在此类中创建一个具有xy作为参数的Residual,但是将遍历此函数和参数,返回其输出的总和。问题是我将无法使用以下方式添加剩余块:

ceres::CostFunction* cost_function1 =
      new ceres::AutoDiffCostFunction<Residual, 1, 1, 1>(
          new Residual(xdata[i], ydata[i]));

由于模板参数<Residual, 1, 1, 1>仅在运行时才知道(最多9个)。

所以我正在寻找一种不同的替代方法,其中我可以分别添加每个残差。 我尝试了一个简单的示例,该示例具有线性残差和柯西(洛伦兹)残差,但是它不起作用。

    std::vector<double> linear_coeffs{0.0, 0.0};
    std::vector<double> lorentz_coeffs{0.0, 0.0};

    ceres::Problem problem;
    for (size_t i = 0; i < xdata.size(); ++i) {

      ceres::CostFunction* cost_function1 =
          new ceres::AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>(
              new ExponentialResidual(xdata[i], ydata[i]));
      problem.AddResidualBlock(cost_function1, nullptr, &linear_coeffs[0],
                               &linear_coeffs[1]);
      ceres::CostFunction* cost_function2 =
          new ceres::AutoDiffCostFunction<LinearResidual, 1, 1, 1>(
              new LinearResidual(xdata[i], ydata[i]));
      problem.AddResidualBlock(cost_function2, nullptr, &lorentz_coeffs[0],
                               &lorentz_coeffs[1]);
    }
Error in evaluating the ResidualBlock.

There are two possible reasons. Either the CostFunction did not evaluate and fill all    
residual and jacobians that were requested or there was a non-finite value (nan/infinite)
generated during the or jacobian computation. 

Residual Block size: 2 parameter blocks x 1 residuals

我检查了文档,但是在结合不同功能的曲线拟合中没有发现任何东西。

有人知道如何使其工作吗?

0 个答案:

没有答案