几何尺寸与公差论坛

 找回密码
 注册
查看: 133|回复: 3

用 CERES 实现 ODR 思路

  [复制链接]
发表于 2024-11-6 15:25:20 | 显示全部楼层 |阅读模式
#include <ceres/ceres.h>
#include <Eigen/Core>

// 定义残差类
struct OrthogonalDistanceResidual {
    OrthogonalDistanceResidual(double observed_x, double observed_y)
        : observed_x(observed_x), observed_y(observed_y) {}

    template <typename T>
    bool operator()(const T* const params, T* residual) const {
        T xc = params[0];
        T yc = params[1];
        T slope = params[2];
        T intercept = params[3];

        // 计算点 (observed_x, observed_y) 到直线 y = slope * x + intercept 的正交距离
        T predicted_y = slope * observed_x + intercept;
        T dx = observed_x - xc;
        T dy = observed_y - yc;

        // 正交距离平方
        residual[0] = dx * dx + dy * dy;
        return true;
    }

private:
    const double observed_x;
    const double observed_y;
};

int main(int argc, char** argv) {
    google::InitGoogleLogging(argv[0]);

    // 模拟数据点
    std::vector<double> x_data = {1.0, 2.0, 3.0};
    std::vector<double> y_data = {2.0, 2.9, 4.1};

    // 初始参数:xc, yc, slope, intercept
    double params[4] = {0.0, 0.0, 1.0, 1.0};

    ceres::Problem problem;
    for (size_t i = 0; i < x_data.size(); ++i) {
        problem.AddResidualBlock(
            new ceres::AutoDiffCostFunction<OrthogonalDistanceResidual, 1, 4>(
                new OrthogonalDistanceResidual(x_data[i], y_data[i])),
            nullptr,
            params);
    }

    ceres::Solver::Options options;
    options.linear_solver_type = ceres::DENSE_QR;
    options.minimizer_progress_to_stdout = true;

    ceres::Solver::Summary summary;
    ceres::Solve(options, &problem, &summary);
    std::cout << summary.FullReport() << "\n";
    std::cout << "Estimated parameters: "
              << "xc=" << params[0] << ", yc=" << params[1]
              << ", slope=" << params[2] << ", intercept=" << params[3] << "\n";

    return 0;
}
 楼主| 发表于 2024-11-6 15:27:03 | 显示全部楼层
此代码使用 CERES Solver 进行非线性最小二乘优化,其中残差是点到模型的正交距离平方,模仿了 ODR 的效果。您可以根据实际需求修改残差定义,调整 params 参数。
 楼主| 发表于 2024-11-6 15:29:10 | 显示全部楼层
ODR (Orthogonal Distance Regression) 是一种回归方法,在拟合模型时最小化每个数据点到模型的正交(垂直)距离。它和传统的最小二乘回归不同,后者只考虑垂直于自变量的距离。ODR 在拟合过程中对误差的分布具有一些特殊属性,使得最大和最小误差可以实现近似的对称分布。这是因为:
对称性与正交距离最小化:
在 ODR 中,距离是正交(垂直)计算的。换句话说,每个数据点到拟合曲线或拟合面的误差是沿着数据点到曲线或曲面最近点的垂直方向计算的。由于正交距离不偏向任何方向,它有助于避免系统性偏差,因此误差的分布更容易对称。正交距离使得拟合曲线能均匀“包围”数据点。
约束条件的平衡:
在该代码中,odrmin 函数内部有多种约束(如 enforce 函数),用于保证初始和迭代中的参数满足某些对称性或物理性条件。这些约束帮助模型参数保持在一个平衡状态,并避免模型偏向某些方向,从而让误差分布更加对称。
信赖域调整与过滤器算法:
代码使用了信赖域调整策略(trust region adjustment)和 CNLP_Filter,这些用于调整参数的迭代步长和接受标准。这些技术用于控制和限制每一步的更新,从而保持模型的稳定和一致性。信赖域方法可以防止模型偏向某些数据点,这样可以让误差更均匀地分布在数据集的两侧。此外,CNLP_Filter 过滤器算法会确保只有满足某些标准的参数更新才能被接受,从而避免误差在特定方向上累积。
修正距离和重新计算步骤:
在 ODR 中,距离的修正和重新计算步骤可以纠正模型拟合中的偏差。例如,代码中的 restore 和 compatible 阶段会进行约束恢复和一致性检查,确保拟合的误差不会偏向某一侧或方向。此外,代码中多次使用 LM_subprob 和 LM_LADsubprob 函数,用于求解子问题并优化残差,进一步平衡误差的分布。
误差和残差的逐步收敛:
ODR 拟合的目标是通过逐步减少残差和最大误差实现收敛,并检查当前误差是否足够小。在代码中,acceptable 和 filter 机制用于检查当前误差是否满足收敛条件。如果误差过大或偏离目标,算法会自动进行调整和限制,逐渐缩小误差范围,使误差最终实现对称分布。
总结
ODR 通过最小化正交距离、利用信赖域和过滤器方法、以及约束的强制执行,实现了误差的对称分布。这种方法不偏向某个特定方向,能够在曲线或曲面两侧均匀分布误差,从而实现了最大误差和最小误差的对称性。
 楼主| 发表于 2024-11-6 15:31:49 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|Archiver|小黑屋|几何尺寸与公差论坛

GMT+8, 2024-12-22 01:47 , Processed in 0.039629 second(s), 21 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表