我目前正在尝试使用Free C++ Extended Kalman Filter Library 。我理解卡尔曼滤波器的基础知识但是我遇到了使用这个库生成NaN值的问题。 SO上有没有人使用卡尔曼滤波算法来发现我的错误?
这是我的过滤器:
class PointEKF : public Kalman::EKFilter<double,1,false,true,false> {
public:
PointEKF() : Period(0.0) {
setDim(3, 1, 3, 1, 1);
}
void SetPeriod(double p) {
Period = p;
}
protected:
void makeBaseA() {
A(1, 1) = 1.0;
//A(1, 2) = Period;
//A(1, 3) = Period*Period / 2;
A(2, 1) = 0.0;
A(2, 2) = 1.0;
//A(2, 3) = Period;
A(3, 1) = 0.0;
A(3, 2) = 0.0;
A(3, 3) = 1.0;
}
void makeBaseH() {
H(1, 1) = 1.0;
H(1, 2) = 0.0;
H(1, 3) = 0.0;
}
void makeBaseV() {
V(1, 1) = 1.0;
}
void makeBaseW() {
W(1, 1) = 1.0;
W(1, 2) = 0.0;
W(1, 3) = 0.0;
W(2, 1) = 0.0;
W(2, 2) = 1.0;
W(2, 3) = 0.0;
W(3, 1) = 0.0;
W(3, 2) = 0.0;
W(3, 3) = 1.0;
}
void makeA() {
double T = Period;
A(1, 1) = 1.0;
A(1, 2) = T;
A(1, 3) = (T*T) / 2;
A(2, 1) = 0.0;
A(2, 2) = 1.0;
A(3, 3) = T;
A(3, 1) = 0.0;
A(3, 2) = 0.0;
A(3, 3) = 1.0;
}
void makeH() {
double T = Period;
H(1, 1) = 1.0;
H(1, 2) = T;
H(1, 3) = T*T / 2;
}
void makeProcess() {
double T = u(1);
Vector x_(x.size());
x_(1) = x(1) + x(2) * T + (x(3) * T*T / 2);
x_(2) = x(2) + x(3) * T;
x_(3) = x(3);
x.swap(x_);
}
void makeMeasure() {
z(1) = x(1);
}
double Period;
};
我用它如下:
void init() {
int n = 3;
static const double _P0[] = {
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0
};
Matrix P0(n, n, _P0);
Vector x(3);
x(1) = getPoint(0);
x(2) = getVelocity(0);
x(3) = getAccleration(0);
filterX.init(x, P0);
}
和
Vector measurement(1), input(1), u(1);
u(1) = 0.400;
double start = data2->positionTimeCounter;
double end = data->positionTimeCounter;
double period = (end - start) / (1000*1000);
filterX.SetPeriod(period);
measurement(1) = getPoint(0);
input(1) = period;
filterX.step(input, measurement);
auto x = filterX.predict(u);
注意: 我使用的数据是从单位圆生成的x点。
答案 0 :(得分:3)
如果您使用矩阵的基本版本:
A = [ 1 0 0;
0 1 0;
0 0 1 ];
H = [ 1 0 0 ];
您没有可观察系统,因为您的测量仅捕获第一个状态(位置),并且A矩阵中没有位置与其导数(速度,加速度)之间的耦合。 observability matrix如下:
O = [ H;
H*A;
H*A*A ];
O = [ 1 0 0;
1 0 0;
1 0 0 ];
这显然是单数的,即你的系统是不可观察的。通过EKF算法提供的信息应产生错误(应该通过算法检测到这种情况),但是如果没有检测到,则会导致NaN结果出现在估算中,与您遇到的情况完全一样。
现在,makeA()函数的A矩阵更合适:
A = [ 1 h h*h/2;
0 1 h;
0 0 1 ];
H = [ 1 0 0 ]; // use this H matrix (not [ 1 h h*h/2 ])
导致可观察性矩阵:
O = [ 1 0 0;
1 h h*h/2;
1 2*h 2*h*h ];
是全等级(不是单数),因此,你有一个可观察的系统。
卡尔曼滤波算法对conditioning of the matrices非常敏感,这意味着如果时间步长非常小(例如1e-6
),则需要使用连续时间版本。此外,NaN的问题可能来自线性求解器(求解线性方程组),这在KF算法中是必需的。如果图书馆的作者使用了一种天真的方法(例如,高斯消元法,有或没有枢轴的LU分解,没有枢轴的Cholesky等),那么这将使这个数值调节问题更加糟糕。
N.B。您应该使用非常高的P矩阵开始KF滤波,因为初始P应该反映初始状态向量的不确定性,通常非常高,因此P应该在1000 * identity
左右。