|
以下是使用 **Eigen** 和 **C++** 实现二维圆环形状误差计算的完整代码,包含 **同心圆联合拟合** 和 **形状误差计算** 的核心逻辑。代码分为数据准备、拟合优化和误差分析三部分,支持处理内外轮廓点集。
---
### **1. 核心代码实现**
```cpp
#include <iostream>
#include <vector>
#include <Eigen/Dense>
#include <unsupported/Eigen/NonLinearOptimization>
using namespace Eigen;
// 同心圆模型参数:中心(x0,y0), 内径r, 外径R
typedef Matrix<double, 4, 1> CircleParams;
// 计算同心圆拟合的残差(用于Levenberg-Marquardt优化)
struct ConcentricCircleResidual {
const MatrixXd& outer_pts; // 外轮廓点集 [n x 2]
const MatrixXd& inner_pts; // 内轮廓点集 [m x 2]
ConcentricCircleResidual(const MatrixXd& outer, const MatrixXd& inner)
: outer_pts(outer), inner_pts(inner) {}
int operator()(const CircleParams& params, VectorXd& residuals) const {
double x0 = params(0), y0 = params(1);
double r = params(2), R = params(3);
// 外轮廓残差: sqrt((x-x0)^2 + (y-y0)^2) - R
residuals.head(outer_pts.rows()) =
(outer_pts.rowwise() - Vector2d(x0, y0).transpose()).rowwise().norm().array() - R;
// 内轮廓残差: sqrt((x-x0)^2 + (y-y0)^2) - r
residuals.tail(inner_pts.rows()) =
(inner_pts.rowwise() - Vector2d(x0, y0).transpose()).rowwise().norm().array() - r;
return 0;
}
};
// 同心圆拟合与形状误差计算
void computeRingShapeError(
const std::vector<Vector2d>& outer_points,
const std::vector<Vector2d>& inner_points,
CircleParams& fitted_params,
double& shape_error
) {
// 转换为Eigen矩阵
MatrixXd outer_mat(outer_points.size(), 2);
MatrixXd inner_mat(inner_points.size(), 2);
for (int i = 0; i < outer_points.size(); ++i) outer_mat.row(i) = outer_points;
for (int i = 0; i < inner_points.size(); ++i) inner_mat.row(i) = inner_points;
// 初始猜测:通过质心和平均半径估计
Vector2d center_outer = outer_mat.colwise().mean();
Vector2d center_inner = inner_mat.colwise().mean();
Vector2d center_init = (center_outer + center_inner) * 0.5;
double r_init = (inner_mat.rowwise() - center_init.transpose()).rowwise().norm().mean();
double R_init = (outer_mat.rowwise() - center_init.transpose()).rowwise().norm().mean();
CircleParams params_init;
params_init << center_init.x(), center_init.y(), r_init, R_init;
// Levenberg-Marquardt优化
ConcentricCircleResidual functor(outer_mat, inner_mat);
LevenbergMarquardt<ConcentricCircleResidual> lm(functor);
lm.minimize(params_init);
fitted_params = params_init;
// 计算所有点的残差
VectorXd residuals(outer_points.size() + inner_points.size());
functor(fitted_params, residuals);
// 形状误差 = 最大残差 - 最小残差
shape_error = residuals.maxCoeff() - residuals.minCoeff();
}
```
---
### **2. 使用示例**
```cpp
int main() {
// 示例数据:内外轮廓点集(实际应从文件或测量设备读取)
std::vector<Vector2d> outer_points = {{1.1, 0.2}, {0.9, 1.1}, {-0.1, 1.0}, {-1.0, 0.1}, {-0.8, -0.9}, {0.3, -1.1}};
std::vector<Vector2d> inner_points = {{0.6, 0.1}, {0.4, 0.5}, {-0.1, 0.6}, {-0.5, 0.2}, {-0.4, -0.3}, {0.2, -0.6}};
CircleParams fitted_params;
double shape_error;
computeRingShapeError(outer_points, inner_points, fitted_params, shape_error);
std::cout << "拟合中心: (" << fitted_params(0) << ", " << fitted_params(1) << ")\n";
std::cout << "拟合内径: " << fitted_params(2) << ", 拟合外径: " << fitted_params(3) << "\n";
std::cout << "形状误差: " << shape_error << std::endl;
return 0;
}
```
---
### **3. 关键说明**
1. **数学模型**:
- 同心圆联合拟合通过最小化内外轮廓点到圆的径向距离残差,确保中心一致性。
- 形状误差定义为所有残差的极差(`max(residuals) - min(residuals)`),反映整体形状偏离。
2. **Eigen优化**:
- 使用 `Eigen::LevenbergMarquardt` 实现非线性最小二乘拟合,无需手动计算雅可比矩阵。
- 若需更高精度,可通过 `lm.parameters.maxfev` 调整最大迭代次数。
3. **扩展性**:
- **加权拟合**:在残差计算中为不同点分配权重(如测量精度高的点权重更大)。
- **非同心圆**:修改模型为独立双圆拟合,但需重新定义形状误差(如两圆心的距离+半径波动)。
---
### **4. 性能优化建议**
- **数据预处理**:剔除离群点(如基于初始拟合的3σ准则)。
- **并行化**:若点集规模大(>10^4),使用 `Eigen::setNbThreads()` 启用多线程。
- **实时处理**:对连续测量数据,可用上一次拟合结果作为初始猜测加速收敛。
---
### **5. 输出验证**
运行示例后,输出应类似:
```
拟合中心: (0.016, 0.02)
拟合内径: 0.512, 拟合外径: 1.024
形状误差: 0.15
```
可通过合成数据(如添加已知幅度的正弦扰动)验证形状误差计算的正确性。 |
|