Могу ли я использовать Ceres Solver, чтобы соответствовать динамически создаваемой кривой? - PullRequest
1 голос
/ 11 октября 2019

Мне нужно подогнать данные к кривой, которую пользователь выбирает в виде суммы предопределенных функций. Идея состоит в том, чтобы создать нечто похожее на то, что 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) Создатькласс подгонки кривой, с членом, который имеет все выбранные функции и массив параметров для каждой из функций. Затем я создал бы Residual внутри этого класса, который имеет x и y в качестве параметров, но будет проходить через эти функции и параметры, возвращая сумму их выходных данных. Проблема в том, что я не смог бы добавить остаточный блок, используя:

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

Я проверил документацию, но я не нашел ничего по подгонке кривой с комбинациейразличные функции.

У кого-нибудь есть идеи, как заставить его работать?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...