带起止导数约束的Eigen三次样条插值实现报错求助
问题分析与解决方案
错误根源在于使用segment()操作处理边界条件时,Eigen的嵌套Block(row()返回的Block对象再调用segment())在节点数n=2的场景下触发了行列越界断言。虽然理论上segment(0,2)对2列矩阵是合法的,但Eigen 3.4.0的Block实现对这种嵌套操作的边界检查存在严格限制,导致断言失败。
修复代码
1. 替换边界条件的segment()操作
将withDerivatives函数中设置边界矩阵行的代码,从依赖segment()改为直接访问矩阵元素,同时先将整行置零,避免嵌套Block操作:
// 原边界条件代码 /* double h0 = x[1] - x[0]; A.row(0).segment(0, 2) = Eigen::RowVector2d{2*h0, h0}; A.row(0).tail(n-2).setZero(); b[0] = 6 * ( (y[1]-y[0])/h0 - m0 ); double hn_1 = x[n-1] - x[n-2]; A.row(n-1).segment(n-2, 2) = Eigen::RowVector2d{hn_1, 2*hn_1}; A.row(n-1).head(n-2).setZero(); b[n-1] = 6 * ( m1 - (y[n-1]-y[n-2])/hn_1 ); */ // 修改后的边界条件代码 // 处理左边界条件 double h0 = x[1] - x[0]; A.row(0).setZero(); A.row(0)(0) = 2 * h0; if (n >= 2) { A.row(0)(1) = h0; } b[0] = 6 * ((y[1] - y[0])/h0 - m0); // 处理右边界条件 double hn_1 = x[n-1] - x[n-2]; A.row(n-1).setZero(); A.row(n-1)(n-1) = 2 * hn_1; if (n >= 2) { A.row(n-1)(n-2) = hn_1; } b[n-1] = 6 * (m1 - (y[n-1] - y[n-2])/hn_1);
2. 添加输入合法性检查
在withDerivatives函数开头增加输入校验,防止非法输入导致后续错误:
if (x.size() != y.size() || x.size() < 2) { throw std::invalid_argument("x and y must have the same size, and at least 2 points"); }
修复效果
修改后代码不再依赖嵌套Block的segment()操作,彻底规避了Eigen的断言触发条件,同时输入检查能提前拦截非法参数。测试场景下程序可正常运行,输出正确的插值结果:Spline at 0.5: 0.5。
内容的提问来源于stack exchange,提问作者skrat
相关产品推荐
相关产品推荐

