英文:
Initialize const ref member variable with Eigen::Ref to matrix
问题
考虑以下类,在其中我想要从传递给构造函数的两个Eigen::Ref中初始化两个成员变量(常规const引用)。
在构造函数内部,下面的打印语句
std::cout << "Matrix Param: " << current_predicted_sigma_points << std::endl;
std::cout << "Matrix Member: " << current_predicted_sigma_points_ << std::endl;
按预期工作,它们打印相同的矩阵,这意味着current_predicted_sigma_points_
已正确初始化。
然而,当我调用Update函数时,变量current_predicted_sigma_points_
包含垃圾值,但weights_
仍然正确。
template <typename ProcessModel, typename MeasurementModel>
class UnscentedUpdateStrategy
{
public:
UnscentedUpdateStrategy(
const Eigen::Ref<const ukf_utils::PredictedSigmaMatrix<ProcessModel, ProcessModel::n_sigma_points>>&
current_predicted_sigma_points,
const Eigen::Ref<const Eigen::Vector<double, ProcessModel::n_sigma_points>>& weights)
: current_predicted_sigma_points_{current_predicted_sigma_points}, weights_{weights}
{
std::cout << "Matrix Param: " << current_predicted_sigma_points << std::endl;
std::cout << "Matrix Member: " << current_predicted_sigma_points_ << std::endl;
}
void Update(const Eigen::Ref<const typename MeasurementModel::PredictedVector>& measure,
const simpleukf::ukf_utils::MeanAndCovariance<ProcessModel>& current_hypotesis,
simpleukf::ukf_utils::MeanAndCovariance<ProcessModel>& mean_and_cov_out) const
{
simpleukf::ukf_utils::PredictedSigmaMatrix<MeasurementModel, ProcessModel::n_sigma_points>
measurement_predicted_sigma_matrix_out;
std::cout << "Matrix Member Update: " << current_predicted_sigma_points_ << std::endl;
std::cout << "Weights Update: " << weights_ << std::endl;
auto measurement_prediction = ukf_utils::PredictMeanAndCovarianceFromSigmaPoints<MeasurementModel>(
measurement_predicted_sigma_matrix_out, current_predicted_sigma_points_, weights_);
// 其余代码...
}
private:
// TODO: should we keep a copy or not?
const ukf_utils::PredictedSigmaMatrix<ProcessModel, ProcessModel::n_sigma_points>&
current_predicted_sigma_points_;
const Eigen::Vector<double, ProcessModel::n_sigma_points>& weights_;
};
当将成员更改为Eigen::Ref类型时,问题消失了,但我想了解原始情况中发生了什么,因为我可能在接受正常引用的嵌套函数中遇到相同的问题。
英文:
Consider the following class where I would like to initialize two member variables (normal const ref) from two Eigen::Ref, passed to the constructor.
Inside the constructor the prints
std::cout << "Matrix Param: " << current_predicted_sigma_points << std::endl;
std::cout << "Matrix Member: " << current_predicted_sigma_points_ << std::endl;
work as expected, they print the same matrix meaning that current_predicted_sigma_points_
is initialized correctly.
Nevertheless, when I call the Update function, the variable current_predicted_sigma_points_
contains garbage but weights_
is still correct.
template <typename ProcessModel, typename MeasurementModel>
class UnscentedUpdateStrategy
{
public:
UnscentedUpdateStrategy(
const Eigen::Ref<const ukf_utils::PredictedSigmaMatrix<ProcessModel, ProcessModel::n_sigma_points>>
current_predicted_sigma_points,
const Eigen::Ref<const Eigen::Vector<double, ProcessModel::n_sigma_points>> weights)
: current_predicted_sigma_points_{current_predicted_sigma_points}, weights_{weights}
{
std::cout << "Matrix Param: " << current_predicted_sigma_points << std::endl;
std::cout << "Matrix Member: " << current_predicted_sigma_points_ << std::endl;
}
void Update(const Eigen::Ref<const typename MeasurementModel::PredictedVector>& measure,
const simpleukf::ukf_utils::MeanAndCovariance<ProcessModel>& current_hypotesis,
simpleukf::ukf_utils::MeanAndCovariance<ProcessModel>& mean_and_cov_out) const
{
simpleukf::ukf_utils::PredictedSigmaMatrix<MeasurementModel, ProcessModel::n_sigma_points>
measurement_predicted_sigma_matrix_out;
std::cout << "Matrix Member Update: " << current_predicted_sigma_points_ << std::endl;
std::cout << "Weights Update: " << weights_ << std::endl;
auto measurement_prediction = ukf_utils::PredictMeanAndCovarianceFromSigmaPoints<MeasurementModel>(
measurement_predicted_sigma_matrix_out, current_predicted_sigma_points_, weights_);
// std::forward<const MeasurementPredictionArgs>(args)...);
// add measurement noise covariance matrix
measurement_prediction.covariance += MeasurementModel::noise_matrix_squared;
// create matrix for cross correlation: predicted measurement `measurement_prediction.mean` and pred covariance
// `measurement_prediction.covariance`
const auto cross_correlation_matrix =
ukf_utils::ComputeCrossCorrelation<ProcessModel, MeasurementModel, ProcessModel::n_sigma_points>(
current_predicted_sigma_points_,
current_hypotesis.mean,
measurement_predicted_sigma_matrix_out,
measurement_prediction.mean,
weights_);
// Kalman gain K;
Eigen::Matrix<double, ProcessModel::n, MeasurementModel::n> K =
cross_correlation_matrix * measurement_prediction.covariance.inverse();
// residual
typename MeasurementModel::PredictedVector measure_diff = measure - measurement_prediction.mean;
// angle normalization
models_utils::AdjustIfNeeded<MeasurementModel>(measure_diff);
// update state mean and covariance matrix
mean_and_cov_out.mean = current_hypotesis.mean + K * measure_diff;
mean_and_cov_out.covariance =
current_hypotesis.covariance - K * measurement_prediction.covariance * K.transpose();
}
private:
// TODO: should we keep a copy or not?
const ukf_utils::PredictedSigmaMatrix<ProcessModel, ProcessModel::n_sigma_points>& current_predicted_sigma_points_;
const Eigen::Vector<double, ProcessModel::n_sigma_points>& weights_;
};
Issues disappear when switching the members to Eigen::Ref types but I would like to understand what is happening in the original case, since I may have the same issues with nested functions taking normal refs.
答案1
得分: 2
你的参数传递有多个问题:
-
你试图从类型为
const Eigen::Ref<const Eigen::Vector<...>>
的对象初始化类型为const Eigen::Vector<...>&
的成员。这两者显然不是相同的类型。其他参数也是同样的情况。 -
你传递了一个
Eigen::Ref
,但希望在函数(在这种情况下是构造函数)的范围之外保留它。出于两个原因,这是不安全的。Ref
通常只是映射你传递的向量或矩阵,但在某些情况下,Ref
将会创建一个临时副本(特别是如果内部步幅大于1,例如当将矩阵的一行作为向量传递时;或者当传递需要评估的表达式时)。这个副本将在引用超出范围时销毁,通常是在函数返回时。此外,
Ref
通常只是通过转换运算符在传递其他东西作为函数参数时构造的。由于Ref
在函数(这里是构造函数)返回时被销毁,保留对此对象的引用或指针将创建一个悬空指针。第二个问题可以通过复制保留
Ref
对象来解决。第一个问题不能通过这种方式解决。所以永远不要这样做。 -
一个小问题是你传递
Ref
的方式。规范的方式是对于输入参数是const Eigen::Ref<const ...>&
,对于输入输出参数是Eigen::Ref<...>
。注意你对于 constRef
没有使用&
。
如何修复这一切?有两个选择:
- 将属性类型更改为普通的
Vector<double, ...>
和PredictedSigmaMatrix
,通过复制Refs
进行构造 - 将构造函数参数更改为普通对象引用、指针、
shared_ptr
或其他,并保留这些指针/引用。不要使用Eigen::Ref
。那只是用于临时引用
英文:
Your argument passing is wrong with multiple issues:
-
You try to initialize a member of type
const Eigen::Vector<...>&
from an object of typeconst Eigen::Ref<const Eigen::Vector<...>>
. Those are clearly not the same type. Same for the other argument -
You pass an
Eigen::Ref
but want to keep it beyond the scope of the function (the constructor in this case). This is unsafe for two reasons.
The Ref
usually simply maps the vector or matrix that you pass but in some cases Ref
will take a temporary copy (specifically if the inner stride is above 1, e.g. when passing a row from a matrix as a vector; or when you pass an expression that needs to be evaluated). This copy will be destroyed when the ref goes out of scope, usually when the function returns.
Additionally, the Ref is usually just constructed via conversion operator when passing something else as the function argument. Since the Ref is destroyed when the function (here the constructor) returns, keeping a reference or pointer to this object creates a dangling pointer.
The second issue can be fixed by keeping a Ref object by copy. The first issue cannot be fixed like that. So never do this.
- A minor issue is the way you pass the Refs. The canonical way is
const Eigen::Ref<const ...>&
for input arguments andEigen::Ref<...>
for in-out arguments. Note that you missed the&
for your const Refs.
How to fix this all? Two options:
- Change the attribute type to plain
Vector<double, ...>
andPredictedSigmaMatrix
, construct by making a copy of the Refs - Change the constructor arguments to plain object references, pointers,
shared_ptr
or whatever and keep those pointers/references. Don't useEigen::Ref
. That's only for temporary references
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论